]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Initial support for POWER Processor decimal floating point instruction
authorJulian Seward <jseward@acm.org>
Mon, 2 Apr 2012 10:20:48 +0000 (10:20 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 2 Apr 2012 10:20:48 +0000 (10:20 +0000)
support -- VEX side changes.  See #295221.

This patch adds the DFP 64-bit and 128-bit support, support for the
new IEEE rounding modes and the Add, Subtract, Multiply and Divide
instructions for both 64-bit and 128-bit instructions to Valgrind.

Carl Love (carll@us.ibm.com) and Maynard Johnson (maynardj@us.ibm.com)

git-svn-id: svn://svn.valgrind.org/vex/trunk@2270

VEX/priv/guest_ppc_helpers.c
VEX/priv/guest_ppc_toIR.c
VEX/priv/host_ppc_defs.c
VEX/priv/host_ppc_defs.h
VEX/priv/host_ppc_isel.c
VEX/priv/ir_defs.c
VEX/priv/ir_opt.c
VEX/pub/libvex_guest_ppc32.h
VEX/pub/libvex_guest_ppc64.h
VEX/pub/libvex_ir.h

index b8a3cd078003e84b1f679f5d8d9587f0e7882121..26ec86f41973c15fbc28bb5ef64e899e16fc9932 100644 (file)
@@ -482,7 +482,8 @@ void LibVEX_GuestPPC32_initialise ( /*OUT*/VexGuestPPC32State* vex_state )
    vex_state->guest_CR7_321 = 0;
    vex_state->guest_CR7_0   = 0;
 
-   vex_state->guest_FPROUND = (UInt)PPCrm_NEAREST;
+   vex_state->guest_FPROUND  = PPCrm_NEAREST;
+   vex_state->guest_DFPROUND = PPCrm_NEAREST;
 
    vex_state->guest_VRSAVE = 0;
 
@@ -638,7 +639,8 @@ void LibVEX_GuestPPC64_initialise ( /*OUT*/VexGuestPPC64State* vex_state )
    vex_state->guest_CR7_321 = 0;
    vex_state->guest_CR7_0   = 0;
 
-   vex_state->guest_FPROUND = (UInt)PPCrm_NEAREST;
+   vex_state->guest_FPROUND  = PPCrm_NEAREST;
+   vex_state->guest_DFPROUND = PPCrm_NEAREST;
 
    vex_state->guest_VRSAVE = 0;
 
index 06e512a6ff510d3145a2efe0f79924f1e8032ca4..85d3b0c311880d08cc7fa6ca2960560e70781352 100644 (file)
@@ -222,6 +222,7 @@ static void* fnptr_to_fnentry( VexAbiInfo* vbi, void* f )
 #define OFFB_XER_CA      offsetofPPCGuestState(guest_XER_CA)
 #define OFFB_XER_BC      offsetofPPCGuestState(guest_XER_BC)
 #define OFFB_FPROUND     offsetofPPCGuestState(guest_FPROUND)
+#define OFFB_DFPROUND    offsetofPPCGuestState(guest_DFPROUND)
 #define OFFB_VRSAVE      offsetofPPCGuestState(guest_VRSAVE)
 #define OFFB_VSCR        offsetofPPCGuestState(guest_VSCR)
 #define OFFB_EMWARN      offsetofPPCGuestState(guest_EMWARN)
@@ -373,8 +374,8 @@ typedef enum {
     PPC_GST_MAX
 } PPC_GST;
 
-#define MASK_FPSCR_RN   0x3
-#define MASK_FPSCR_FPRF 0x1F000
+#define MASK_FPSCR_RN   0x3ULL  // Binary floating point rounding mode
+#define MASK_FPSCR_DRN  0x700000000ULL // Decimal floating point rounding mode
 #define MASK_VSCR_VALID 0x00010001
 
 
@@ -415,7 +416,6 @@ static UInt MASK32( UInt begin, UInt end )
    return mask;
 }
 
-/* ditto for 64bit mask */
 static ULong MASK64( UInt begin, UInt end )
 {
    ULong m1, m2, mask;
@@ -1114,6 +1114,45 @@ static void putFReg ( UInt archreg, IRExpr* e )
    stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
 }
 
+/* get Decimal float value.  Note, they share floating point register file. */
+static IRExpr* getDReg(UInt archreg) {
+   IRExpr *e;
+   vassert( archreg < 32 );
+   e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D64 );
+   return e;
+}
+
+/* Read a floating point register pair and combine their contents into a
+ 128-bit value */
+static IRExpr *getDReg_pair(UInt archreg) {
+   IRExpr *high = getDReg( archreg );
+   IRExpr *low = getDReg( archreg + 1 );
+
+   return binop( Iop_D64HLtoD128, high, low );
+}
+
+/* Ditto, but write to a reg instead. */
+static void putDReg(UInt archreg, IRExpr* e) {
+   vassert( archreg < 32 );
+   vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D64 );
+   stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
+}
+
+/* Write a 128-bit floating point value into a register pair. */
+static void putDReg_pair(UInt archreg, IRExpr *e) {
+   IRTemp low = newTemp( Ity_D64 );
+   IRTemp high = newTemp( Ity_D64 );
+
+   vassert( archreg < 32 );
+   vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D128 );
+
+   assign( low, unop( Iop_D128LOtoD64, e ) );
+   assign( high, unop( Iop_D128HItoD64, e ) );
+
+   stmt( IRStmt_Put( floatGuestRegOffset( archreg ), mkexpr( high ) ) );
+   stmt( IRStmt_Put( floatGuestRegOffset( archreg + 1 ), mkexpr( low ) ) );
+}
+
 static Int vsxGuestRegOffset ( UInt archreg )
 {
    vassert(archreg < 64);
@@ -2464,10 +2503,12 @@ static IRExpr* /* ::Ity_I32 */ getGST_masked ( PPC_GST reg, UInt mask )
          all exceptions masked, round-to-nearest.
          This corresponds to a FPSCR value of 0x0. */
 
-      /* We're only keeping track of the rounding mode,
-         so if the mask isn't asking for this, just return 0x0 */
-      if (mask & (MASK_FPSCR_RN|MASK_FPSCR_FPRF)) {
-         assign( val, IRExpr_Get( OFFB_FPROUND, Ity_I32 ) );
+      /* In the lower 32 bits of FPSCR, we're only keeping track of
+       * the binary floating point rounding mode, so if the mask isn't
+       * asking for this, just return 0x0.
+       */
+      if (mask & MASK_FPSCR_RN) {
+         assign( val, unop( Iop_8Uto32, IRExpr_Get( OFFB_FPROUND, Ity_I8 ) ) );
       } else {
          assign( val, mkU32(0x0) );
       }
@@ -2486,6 +2527,36 @@ static IRExpr* /* ::Ity_I32 */ getGST_masked ( PPC_GST reg, UInt mask )
    }
 }
 
+/* Get a masked word from the given reg */
+static IRExpr* /* ::Ity_I32 */getGST_masked_upper(PPC_GST reg, ULong mask) {
+   IRExpr * val;
+   vassert( reg < PPC_GST_MAX );
+
+   switch (reg) {
+
+   case PPC_GST_FPSCR: {
+      /* In the upper 32 bits of FPSCR, we're only keeping track
+       * of the decimal floating point rounding mode, so if the mask
+       * isn't asking for this, just return 0x0.
+       */
+      if (mask & MASK_FPSCR_DRN) {
+         val = binop( Iop_And32,
+                      unop( Iop_8Uto32, IRExpr_Get( OFFB_DFPROUND, Ity_I8 ) ),
+                      unop( Iop_64HIto32, mkU64( mask ) ) );
+      } else {
+         val = mkU32( 0x0ULL );
+      }
+      break;
+   }
+
+   default:
+      vex_printf( "getGST_masked_upper(ppc): reg = %u", reg );
+      vpanic( "getGST_masked_upper(ppc)" );
+   }
+   return val;
+}
+
+
 /* Fetch the specified REG[FLD] nibble (as per IBM/hardware notation)
    and return it at the bottom of an I32; the top 27 bits are
    guaranteed to be zero. */
@@ -2581,32 +2652,30 @@ static void putGST ( PPC_GST reg, IRExpr* src )
 }
 
 /* Write masked src to the given reg */
-static void putGST_masked ( PPC_GST reg, IRExpr* src, UInt mask )
+static void putGST_masked ( PPC_GST reg, IRExpr* src, ULong mask )
 {
    IRType ty = mode64 ? Ity_I64 : Ity_I32;
    vassert( reg < PPC_GST_MAX );
-   vassert( typeOfIRExpr(irsb->tyenv,src ) == Ity_I32 );
-   
+   vassert( typeOfIRExpr( irsb->tyenv,src ) == Ity_I64 );
+
    switch (reg) {
    case PPC_GST_FPSCR: {
-      /* Allow writes to Rounding Mode */
-      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( 
-            IRStmt_Put( 
-               OFFB_FPROUND,
-               binop(
-                  Iop_Or32, 
-                  binop(Iop_And32, src, mkU32((MASK_FPSCR_RN|MASK_FPSCR_FPRF) & mask)),
-                  binop(
-                     Iop_And32, 
-                     IRExpr_Get(OFFB_FPROUND,Ity_I32),
-                     mkU32((MASK_FPSCR_RN|MASK_FPSCR_FPRF) & ~mask)
-                  )
-               )
-            )
-         );
+      /* Allow writes to either binary or decimal floating point
+       * Rounding Mode
+       */
+      if (mask & MASK_FPSCR_RN) {
+         stmt( IRStmt_Put( OFFB_FPROUND,
+                           unop( Iop_32to8,
+                                 binop( Iop_And32,
+                                        unop( Iop_64to32, src ),
+                                        mkU32( MASK_FPSCR_RN & mask ) ) ) ) );
+      } else if (mask & MASK_FPSCR_DRN) {
+         stmt( IRStmt_Put( OFFB_DFPROUND,
+                           unop( Iop_32to8,
+                                 binop( Iop_And32,
+                                        unop( Iop_64HIto32, src ),
+                                        mkU32( ( MASK_FPSCR_DRN & mask )
+                                                 >> 32 ) ) ) ) );
       }
 
       /* Give EmWarn for attempted writes to:
@@ -2641,13 +2710,17 @@ static void putGST_masked ( PPC_GST reg, IRExpr* src, UInt mask )
    REG[FLD] (as per IBM/hardware notation). */
 static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
 {
-   UInt shft, mask;
+   UInt shft;
+   ULong mask;
 
    vassert( typeOfIRExpr(irsb->tyenv,src ) == Ity_I32 );
-   vassert( fld < 8 );
+   vassert( fld < 16 );
    vassert( reg < PPC_GST_MAX );
    
-   shft = 4*(7-fld);
+   if (fld < 8)
+      shft = 4*(7-fld);
+   else
+      shft = 4*(15-fld);
    mask = 0xF<<shft;
 
    switch (reg) {
@@ -2657,12 +2730,16 @@ static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
       break;
 
    default:
-      if (shft == 0) {
-         putGST_masked( reg, src, mask );
-      } else {
-         putGST_masked( reg,
-                        binop(Iop_Shl32, src, mkU8(toUChar(shft))),
-                        mask );
+      {
+         IRExpr * src64 = unop( Iop_32Uto64, src );
+
+         if (shft == 0) {
+            putGST_masked( reg, src64, mask );
+         } else {
+            putGST_masked( reg,
+                           binop( Iop_Shl64, src64, mkU8( toUChar( shft ) ) ),
+                           mask );
+         }
       }
    }
 }
@@ -6689,6 +6766,33 @@ static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode ( void )
                         mkU32(2) ));
 }
 
+/* The DFP IR rounding modes were chosen such that the existing PPC to IR
+ * mapping would still work with the extended three bit DFP rounding 
+ * mode designator.
+
+ *  rounding mode                     | PPC  |  IR
+ *  -----------------------------------------------
+ *  to nearest, ties to even          | 000  | 000
+ *  to zero                           | 001  | 011
+ *  to +infinity                      | 010  | 010
+ *  to -infinity                      | 011  | 001
+ *  to nearest, ties away from 0      | 100  | 100
+ *  to nearest, ties toward 0         | 101  | 111
+ *  to away from 0                    | 110  | 110
+ *  to prepare for shorter precision  | 111  | 101
+ */
+static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode_DFP( void )
+{
+   IRTemp rm_PPC32 = newTemp( Ity_I32 );
+   assign( rm_PPC32, getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN ) );
+
+   // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
+   return binop( Iop_Xor32,
+                 mkexpr( rm_PPC32 ),
+                 binop( Iop_And32,
+                        binop( Iop_Shl32, mkexpr( rm_PPC32 ), mkU8( 1 ) ),
+                        mkU32( 2 ) ) );
+}
 
 /*------------------------------------------------------------*/
 /*--- Floating Point Instruction Translation               ---*/
@@ -8224,7 +8328,7 @@ static Bool dis_fp_move ( UInt theInstr )
 /*
   Floating Point Status/Control Register Instructions
 */
-static Bool dis_fp_scr ( UInt theInstr )
+static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
 {
    /* Many forms - see each switch case */
    UChar opc1    = ifieldOPC(theInstr);
@@ -8247,7 +8351,8 @@ static Bool dis_fp_scr ( UInt theInstr )
          return False;
       }
       DIP("mtfsb1%s crb%d \n", flag_rC ? ".":"", crbD);
-      putGST_masked( PPC_GST_FPSCR, mkU32(1<<(31-crbD)), 1<<(31-crbD) );
+      putGST_masked( PPC_GST_FPSCR, mkU64( 1 <<( 31 - crbD ) ),
+                    1ULL << ( 31 - crbD ) );
       break;
    }
 
@@ -8283,29 +8388,41 @@ static Bool dis_fp_scr ( UInt theInstr )
          return False;
       }      
       DIP("mtfsb0%s crb%d\n", flag_rC ? ".":"", crbD);
-      putGST_masked( PPC_GST_FPSCR, mkU32(0), 1<<(31-crbD) );
+      putGST_masked( PPC_GST_FPSCR, mkU64( 0 ), 1ULL << ( 31 - crbD ) );
       break;
    }
 
    case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
-      UChar crfD    = toUChar( IFIELD( theInstr, 23, 3 ) );
+      UInt crfD     = IFIELD( theInstr, 23, 3 );
       UChar b16to22 = toUChar( IFIELD( theInstr, 16, 7 ) );
       UChar IMM     = toUChar( IFIELD( theInstr, 12, 4 ) );
       UChar b11     = toUChar( IFIELD( theInstr, 11, 1 ) );
+      UChar Wbit;
 
       if (b16to22 != 0 || b11 != 0) {
          vex_printf("dis_fp_scr(ppc)(instr,mtfsfi)\n");
          return False;
       }      
       DIP("mtfsfi%s crf%d,%d\n", flag_rC ? ".":"", crfD, IMM);
-      putGST_field( PPC_GST_FPSCR, mkU32(IMM), crfD );
+      if (GX_level) {
+         /* This implies that Decimal Floating Point is supported, and the
+          * FPSCR must be managed as a 64-bit register.
+          */
+         Wbit = toUChar( IFIELD(theInstr, 16, 1) );
+      } else {
+         Wbit = 0;
+      }
+      crfD = crfD + (8 * (1 - Wbit) );
+      putGST_field( PPC_GST_FPSCR, mkU32( IMM ), crfD );
       break;
    }
 
    case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
       UChar   frD_addr  = ifieldRegDS(theInstr);
       UInt    b11to20   = IFIELD(theInstr, 11, 10);
-      IRExpr* fpscr_all = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
+      IRExpr* fpscr_lower = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
+      IRExpr* fpscr_upper = getGST_masked_upper( PPC_GST_FPSCR,
+                                                 MASK_FPSCR_DRN );
 
       if (b11to20 != 0) {
          vex_printf("dis_fp_scr(ppc)(instr,mffs)\n");
@@ -8314,7 +8431,7 @@ static Bool dis_fp_scr ( UInt theInstr )
       DIP("mffs%s fr%u\n", flag_rC ? ".":"", frD_addr);
       putFReg( frD_addr,
           unop( Iop_ReinterpI64asF64,
-                unop( Iop_32Uto64, fpscr_all )));
+                binop( Iop_32HLto64, fpscr_upper, fpscr_lower ) ) );
       break;
    }
 
@@ -8323,8 +8440,21 @@ static Bool dis_fp_scr ( UInt theInstr )
       UChar FM       = toUChar( IFIELD(theInstr, 17, 8) );
       UChar frB_addr = ifieldRegB(theInstr);
       IRTemp frB   = newTemp(Ity_F64);
-      IRTemp rB_32 = newTemp(Ity_I32);
-      Int i, mask;
+      IRTemp rB_64 = newTemp( Ity_I64 );
+      Int i;
+      ULong mask;
+      UChar Wbit;
+#define BFP_MASK_SEED 0x3000000000000000ULL
+#define DFP_MASK_SEED 0x7000000000000000ULL
+
+      if (GX_level) {
+         /* This implies that Decimal Floating Point is supported, and the
+          * FPSCR must be managed as a 64-bit register.
+          */
+         Wbit = toUChar( IFIELD(theInstr, 16, 1) );
+      } else {
+         Wbit = 0;
+      }
 
       if (b25 == 1) {
          /* new 64 bit move variant for power 6.  If L field (bit 25) is
@@ -8342,14 +8472,24 @@ static Bool dis_fp_scr ( UInt theInstr )
          mask = 0;
          for (i=0; i<8; i++) {
             if ((FM & (1<<(7-i))) == 1) {
-               mask |= 0xF << (7-i);
+               /* FPSCR field k is set to the contents of the corresponding
+                * field of register FRB, where k = i+8x(1-W).  In the Power
+                * ISA, register field numbering is from left to right, so field
+                * 15 is the least significant field in a 64-bit register.  To
+                * generate the mask, we set all the appropriate rounding mode
+                * bits in the highest order nibble (field 0) and shift right 
+                * 'k x nibble length'.
+                */
+               if (Wbit)
+                  mask |= DFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
+               else
+                  mask |= BFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
             }
          }
       }
       assign( frB, getFReg(frB_addr));
-      assign( rB_32, unop( Iop_64to32,
-                           unop( Iop_ReinterpF64asI64, mkexpr(frB) )));
-      putGST_masked( PPC_GST_FPSCR, mkexpr(rB_32), mask );
+      assign( rB_64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
+      putGST_masked( PPC_GST_FPSCR, mkexpr( rB_64 ), mask );
       break;
    }
 
@@ -8360,7 +8500,124 @@ static Bool dis_fp_scr ( UInt theInstr )
    return True;
 }
 
+/*------------------------------------------------------------*/
+/*--- Decimal Floating Point (DFP) instruction translation ---*/
+/*------------------------------------------------------------*/
+/* DFP Arithmetic instructions */
+static Bool dis_dfp_arith(UInt theInstr)
+{
+   UInt opc2 = ifieldOPClo10( theInstr );
+   UChar frS_addr = ifieldRegDS( theInstr );
+   UChar frA_addr = ifieldRegA( theInstr );
+   UChar frB_addr = ifieldRegB( theInstr );
+   UChar flag_rC = ifieldBIT0( theInstr );
+
+   IRTemp frA = newTemp( Ity_D64 );
+   IRTemp frB = newTemp( Ity_D64 );
+   IRTemp frS = newTemp( Ity_D64 );
+   IRExpr* round = get_IR_roundingmode_DFP();
+
+   /* By default, if flag_RC is set, we will clear cr1 after the
+    * operation.  In reality we should set cr1 to indicate the
+    * exception status of the operation, but since we're not
+    * 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;
+
+   assign( frA, getDReg( frA_addr ) );
+   assign( frB, getDReg( frB_addr ) );
 
+   switch (opc2) {
+   case 0x2: // dadd
+      DIP( "dadd%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_AddD64, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   case 0x202: // dsub
+      DIP( "dsub%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_SubD64, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   case 0x22: // dmul
+      DIP( "dmul%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_MulD64, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   case 0x222: // ddiv
+      DIP( "ddiv%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_DivD64, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   }
+
+   putDReg( frS_addr, mkexpr( frS ) );
+
+   if (flag_rC && clear_CR1) {
+      putCR321( 1, mkU8( 0 ) );
+      putCR0( 1, mkU8( 0 ) );
+   }
+
+   return True;
+}
+
+/* Quad DFP Arithmetic instructions */
+static Bool dis_dfp_arithq(UInt theInstr)
+{
+   UInt opc2 = ifieldOPClo10( theInstr );
+   UChar frS_addr = ifieldRegDS( theInstr );
+   UChar frA_addr = ifieldRegA( theInstr );
+   UChar frB_addr = ifieldRegB( theInstr );
+   UChar flag_rC = ifieldBIT0( theInstr );
+
+   IRTemp frA = newTemp( Ity_D128 );
+   IRTemp frB = newTemp( Ity_D128 );
+   IRTemp frS = newTemp( Ity_D128 );
+   IRExpr* round = get_IR_roundingmode_DFP();
+
+   /* By default, if flag_RC is set, we will clear cr1 after the
+    * operation.  In reality we should set cr1 to indicate the
+    * exception status of the operation, but since we're not
+    * 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;
+
+   assign( frA, getDReg_pair( frA_addr ) );
+   assign( frB, getDReg_pair( frB_addr ) );
+
+   switch (opc2) {
+   case 0x2: // daddq
+      DIP( "daddq%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_AddD128, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   case 0x202: // dsubq
+      DIP( "dsubq%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_SubD128, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   case 0x22: // dmulq
+      DIP( "dmulq%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_MulD128, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   case 0x222: // ddivq
+      DIP( "ddivq%s fr%u,fr%u,fr%u\n",
+           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+      assign( frS, triop( Iop_DivD128, round, mkexpr( frA ), mkexpr( frB ) ) );
+      break;
+   }
+
+   putDReg_pair( frS_addr, mkexpr( frS ) );
+
+   if (flag_rC && clear_CR1) {
+      putCR321( 1, mkU8( 0 ) );
+      putCR0( 1, mkU8( 0 ) );
+   }
+
+   return True;
+}
 
 /*------------------------------------------------------------*/
 /*--- AltiVec Instruction Translation                      ---*/
@@ -13542,7 +13799,15 @@ DisResult disInstr_PPC_WRK (
    case 0x3B:
       if (!allow_F) goto decode_noF;
       opc2 = ifieldOPClo10(theInstr);
+
       switch (opc2) {
+         case 0x2:    // dadd - DFP Add
+         case 0x202:  // dsub - DFP Subtract
+         case 0x22:   // dmul - DFP Mult
+         case 0x222:  // ddiv - DFP Divide
+           if (!allow_GX) goto decode_failure;
+            if (dis_dfp_arith( theInstr ))
+               goto decode_success;
          case 0x3CE: // fcfidus (implemented as native insn)
             if (!allow_VX)
                goto decode_noVX;
@@ -13759,6 +14024,16 @@ DisResult disInstr_PPC_WRK (
 
       opc2 = IFIELD(theInstr, 1, 10);
       switch (opc2) {
+      /* 128-bit DFP instructions */
+      case 0x2:    // daddq - DFP Add
+      case 0x202:  // dsubq - DFP Subtract
+      case 0x22:   // dmulq - DFP Mult
+      case 0x222:  // ddivq - DFP Divide
+         if (!allow_GX) goto decode_failure;
+         if (dis_dfp_arithq( theInstr ))
+            goto decode_success;
+         goto decode_failure;
+
       /* Floating Point Compare Instructions */         
       case 0x000: // fcmpu
       case 0x020: // fcmpo
@@ -13812,7 +14087,9 @@ DisResult disInstr_PPC_WRK (
       case 0x086: // mtfsfi
       case 0x247: // mffs
       case 0x2C7: // mtfsf
-         if (dis_fp_scr( theInstr )) goto decode_success;
+         // Some of the above instructions need to know more about the
+         // ISA level supported by the host.
+         if (dis_fp_scr( theInstr, allow_GX )) goto decode_success;
          goto decode_failure;
 
       default:
index cac5a5c5431137573958d090d4041c242a1ec416..9229e11cd81f9de48c21cb04974dfa389ceb8110 100644 (file)
@@ -630,6 +630,14 @@ HChar* showPPCFpOp ( PPCFpOp op ) {
       case Pfp_FRIN:   return "frin";
       case Pfp_FRIP:   return "frip";
       case Pfp_FRIZ:   return "friz";
+      case Pfp_DFPADD:     return "dadd";
+      case Pfp_DFPADDQ:    return "daddq";
+      case Pfp_DFPSUB:     return "dsub";
+      case Pfp_DFPSUBQ:    return "dsubq";
+      case Pfp_DFPMUL:     return "dmul";
+      case Pfp_DFPMULQ:    return "dmulq";
+      case Pfp_DFPDIV:     return "ddivd";
+      case Pfp_DFPDIVQ:    return "ddivq";
       default: vpanic("showPPCFpOp");
    }
 }
@@ -970,6 +978,35 @@ PPCInstr* PPCInstr_FpRSP ( HReg dst, HReg src ) {
    i->Pin.FpRSP.src = src;
    return i;
 }
+PPCInstr* PPCInstr_Dfp64Unary(PPCFpOp op, HReg dst, HReg src) {
+   PPCInstr* i = LibVEX_Alloc( sizeof(PPCInstr) );
+   i->tag = Pin_Dfp64Unary;
+   i->Pin.Dfp64Unary.op = op;
+   i->Pin.Dfp64Unary.dst = dst;
+   i->Pin.Dfp64Unary.src = src;
+   return i;
+}
+PPCInstr* PPCInstr_Dfp64Binary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) {
+   PPCInstr* i = LibVEX_Alloc( sizeof(PPCInstr) );
+   i->tag = Pin_Dfp64Binary;
+   i->Pin.Dfp64Binary.op = op;
+   i->Pin.Dfp64Binary.dst = dst;
+   i->Pin.Dfp64Binary.srcL = srcL;
+   i->Pin.Dfp64Binary.srcR = srcR;
+   return i;
+}
+PPCInstr* PPCInstr_Dfp128Binary(PPCFpOp op, HReg dst_hi, HReg dst_lo,
+                                HReg srcR_hi, HReg srcR_lo) {
+   /* dst is used to pass the srcL argument and return the result */
+   PPCInstr* i = LibVEX_Alloc( sizeof(PPCInstr) );
+   i->tag = Pin_Dfp128Binary;
+   i->Pin.Dfp128Binary.op = op;
+   i->Pin.Dfp128Binary.dst_hi = dst_hi;
+   i->Pin.Dfp128Binary.dst_lo = dst_lo;
+   i->Pin.Dfp128Binary.srcR_hi = srcR_hi;
+   i->Pin.Dfp128Binary.srcR_lo = srcR_lo;
+   return i;
+}
 
 /*
 Valid combo | fromI | int32 | syned | flt64 |
@@ -1040,10 +1077,11 @@ PPCInstr* PPCInstr_FpCMov ( PPCCondCode cond, HReg dst, HReg src ) {
    vassert(cond.test != Pct_ALWAYS);
    return i;
 }
-PPCInstr* PPCInstr_FpLdFPSCR ( HReg src ) {
+PPCInstr* PPCInstr_FpLdFPSCR ( HReg src, Bool dfp_rm ) {
    PPCInstr* i          = LibVEX_Alloc(sizeof(PPCInstr));
    i->tag               = Pin_FpLdFPSCR;
    i->Pin.FpLdFPSCR.src = src;
+   i->Pin.FpLdFPSCR.dfp_rm = dfp_rm ? 1 : 0;
    return i;
 }
 PPCInstr* PPCInstr_FpCmp ( HReg dst, HReg srcL, HReg srcR ) {
@@ -1547,6 +1585,7 @@ void ppPPCInstr ( PPCInstr* i, Bool mode64 )
    case Pin_FpLdFPSCR:
       vex_printf("mtfsf 0xFF,");
       ppHRegPPC(i->Pin.FpLdFPSCR.src);
+      vex_printf(",0, %s", i->Pin.FpLdFPSCR.dfp_rm ? "1" : "0");
       return;
    case Pin_FpCmp:
       vex_printf("fcmpo %%cr1,");
@@ -1711,6 +1750,29 @@ void ppPPCInstr ( PPCInstr* i, Bool mode64 )
       ppHRegPPC(i->Pin.AvLdVSCR.src);
       return;
 
+   case Pin_Dfp64Unary:
+      vex_printf("%s ", showPPCFpOp(i->Pin.Dfp64Unary.op));
+      ppHRegPPC(i->Pin.Dfp64Unary.dst);
+      vex_printf(",");
+      ppHRegPPC(i->Pin.Dfp64Unary.src);
+      return;
+
+   case Pin_Dfp64Binary:
+      vex_printf("%s ", showPPCFpOp(i->Pin.Dfp64Binary.op));
+      ppHRegPPC(i->Pin.Dfp64Binary.dst);
+      vex_printf(",");
+      ppHRegPPC(i->Pin.Dfp64Binary.srcL);
+      vex_printf(",");
+      ppHRegPPC(i->Pin.Dfp64Binary.srcR);
+      return;
+
+   case Pin_Dfp128Binary:
+      vex_printf("%s ", showPPCFpOp(i->Pin.Dfp128Binary.op));
+      ppHRegPPC(i->Pin.Dfp128Binary.dst_hi);
+      vex_printf(",");
+      ppHRegPPC(i->Pin.Dfp128Binary.srcR_hi);
+      return;
+
    default:
       vex_printf("\nppPPCInstr: No such tag(%d)\n", (Int)i->tag);
       vpanic("ppPPCInstr");
@@ -1978,6 +2040,21 @@ void getRegUsage_PPCInstr ( HRegUsage* u, PPCInstr* i, Bool mode64 )
    case Pin_AvLdVSCR:
       addHRegUse(u, HRmRead, i->Pin.AvLdVSCR.src);
       return;
+   case Pin_Dfp64Unary:
+      addHRegUse(u, HRmWrite, i->Pin.Dfp64Unary.dst);
+      addHRegUse(u, HRmRead, i->Pin.Dfp64Unary.src);
+      return;
+   case Pin_Dfp64Binary:
+      addHRegUse(u, HRmWrite, i->Pin.Dfp64Binary.dst);
+      addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcL);
+      addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcR);
+      return;
+   case Pin_Dfp128Binary:
+      addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_hi);
+      addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_lo);
+      addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_hi);
+      addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_lo);
+      return;
 
    default:
       ppPPCInstr(i, mode64);
@@ -2174,6 +2251,21 @@ void mapRegs_PPCInstr ( HRegRemap* m, PPCInstr* i, Bool mode64 )
    case Pin_AvLdVSCR:
       mapReg(m, &i->Pin.AvLdVSCR.src);
       return;
+   case Pin_Dfp64Unary:
+      mapReg(m, &i->Pin.Dfp64Unary.dst);
+      mapReg(m, &i->Pin.Dfp64Unary.src);
+      return;
+   case Pin_Dfp64Binary:
+      mapReg(m, &i->Pin.Dfp64Binary.dst);
+      mapReg(m, &i->Pin.Dfp64Binary.srcL);
+      mapReg(m, &i->Pin.Dfp64Binary.srcR);
+      return;
+   case Pin_Dfp128Binary:
+      mapReg(m, &i->Pin.Dfp128Binary.dst_hi);
+      mapReg(m, &i->Pin.Dfp128Binary.dst_lo);
+      mapReg(m, &i->Pin.Dfp128Binary.srcR_hi);
+      mapReg(m, &i->Pin.Dfp128Binary.srcR_lo);
+      return;
 
    default:
       ppPPCInstr(i, mode64);
@@ -2423,12 +2515,12 @@ static UChar* mkFormXFX ( UChar* p, UInt r1, UInt f2, UInt opc2 )
 }
 
 // Only used by mtfsf
-static UChar* mkFormXFL ( UChar* p, UInt FM, UInt freg )
+static UChar* mkFormXFL ( UChar* p, UInt FM, UInt freg, UInt dfp_rm )
 {
    UInt theInstr;
    vassert(FM   < 0x100);
    vassert(freg < 0x20);
-   theInstr = ((63<<26) | (FM<<17) | (freg<<11) | (711<<1));
+   theInstr = ((63<<26) | (FM<<17) | (dfp_rm<<16) | (freg<<11) | (711<<1));
    return emit32(p, theInstr);
 }
 
@@ -3533,7 +3625,7 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i,
 
    case Pin_FpLdFPSCR: {
       UInt fr_src = fregNo(i->Pin.FpLdFPSCR.src);
-      p = mkFormXFL(p, 0xFF, fr_src);     // mtfsf, PPC32 p480
+      p = mkFormXFL(p, 0xFF, fr_src, i->Pin.FpLdFPSCR.dfp_rm);     // mtfsf, PPC32 p480
       goto done;
    }
 
@@ -3950,6 +4042,93 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i,
       goto done;
    }
 
+   case Pin_Dfp64Unary: {
+      UInt fr_dst = fregNo( i->Pin.FpUnary.dst );
+      UInt fr_src = fregNo( i->Pin.FpUnary.src );
+
+      switch (i->Pin.Dfp64Unary.op) {
+      case Pfp_MOV: // fmr, PPC32 p410
+         p = mkFormX( p, 63, fr_dst, 0, fr_src, 72, 0 );
+         break;
+      default:
+         goto bad;
+      }
+      goto done;
+   }
+
+   case Pin_Dfp64Binary: {
+      UInt fr_dst = fregNo( i->Pin.Dfp64Binary.dst );
+      UInt fr_srcL = fregNo( i->Pin.Dfp64Binary.srcL );
+      UInt fr_srcR = fregNo( i->Pin.Dfp64Binary.srcR );
+      switch (i->Pin.Dfp64Binary.op) {
+      case Pfp_DFPADD: /* dadd, dfp add, use default RM from reg ignore mode
+                        * from the Iop instruction. */
+         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 2, 0 );
+         break;
+      case Pfp_DFPSUB: /* dsub, dfp subtract, use default RM from reg ignore
+                        * mode from the Iop instruction. */
+         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 514, 0 );
+         break;
+      case Pfp_DFPMUL: /* dmul, dfp multipy, use default RM from reg ignore
+                        * mode from the Iop instruction. */
+         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 34, 0 );
+         break;
+      case Pfp_DFPDIV: /* ddiv, dfp divide, use default RM from reg ignore
+                        * mode from the Iop instruction. */
+         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 546, 0 );
+         break;
+      default:
+         goto bad;
+      }
+      goto done;
+   }
+
+   case Pin_Dfp128Binary: {
+      /* dst is used to supply the  left source operand and return
+       * the result.
+       */
+      UInt fr_dstHi = fregNo( i->Pin.Dfp128Binary.dst_hi );
+      UInt fr_dstLo = fregNo( i->Pin.Dfp128Binary.dst_lo );
+      UInt fr_srcRHi = fregNo( i->Pin.Dfp128Binary.srcR_hi );
+      UInt fr_srcRLo = fregNo( i->Pin.Dfp128Binary.srcR_lo );
+
+      /* Setup the upper and lower registers of the source operand
+       * register pair.
+       */
+      p = mkFormX( p, 63, 10, 0, fr_dstHi, 72, 0 );
+      p = mkFormX( p, 63, 11, 0, fr_dstLo, 72, 0 );
+      p = mkFormX( p, 63, 12, 0, fr_srcRHi, 72, 0 );
+      p = mkFormX( p, 63, 13, 0, fr_srcRLo, 72, 0 );
+
+      /* Do instruction with 128-bit source operands in registers (10,11)
+       * and (12,13).
+       */
+      switch (i->Pin.Dfp128Binary.op) {
+      case Pfp_DFPADDQ:
+         p = mkFormX( p, 63, 10, 10, 12, 2, 0 );
+         break;
+      case Pfp_DFPSUBQ:
+         p = mkFormX( p, 63, 10, 10, 12, 514, 0 );
+         break;
+      case Pfp_DFPMULQ:
+         p = mkFormX( p, 63, 10, 10, 12, 34, 0 );
+         break;
+      case Pfp_DFPDIVQ:
+         p = mkFormX( p, 63, 10, 10, 12, 546, 0 );
+         break;
+      default:
+         goto bad;
+      }
+
+      /* The instruction will put the 128-bit result in
+       * registers (10,11).  Note, the operand in the instruction only
+       * reference the first of the two registers in the pair.
+       */
+      p = mkFormX(p, 63, fr_dstHi, 0, 10,  72, 0);
+      p = mkFormX(p, 63, fr_dstLo, 0, 11,  72, 0);
+      goto done;
+   }
+
    default: 
       goto bad;
    }
index 58ddb4327aa8fe8260cbc11ef0c45b07e8cb94b5..9f6797bd633a108979ae860875b46d023859ebbb 100644 (file)
@@ -359,8 +359,13 @@ typedef
       Pfp_INVALID,
 
       /* Ternary */
-      Pfp_MADDD, Pfp_MSUBD, 
-      Pfp_MADDS, Pfp_MSUBS,
+      Pfp_MADDD,  Pfp_MSUBD,
+      Pfp_MADDS,  Pfp_MSUBS,
+      Pfp_DFPADD, Pfp_DFPADDQ,
+      Pfp_DFPSUB, Pfp_DFPSUBQ,
+      Pfp_DFPMUL, Pfp_DFPMULQ,
+      Pfp_DFPDIV, Pfp_DFPDIVQ,
+      Pfp_DQUAQ,  Pfp_DRRNDQ,
 
       /* Binary */
       Pfp_ADDD, Pfp_SUBD, Pfp_MULD, Pfp_DIVD, 
@@ -485,7 +490,11 @@ typedef
       Pin_AvShlDbl,   /* AV shift-left double by imm */
       Pin_AvSplat,    /* One elem repeated throughout dst */
       Pin_AvLdVSCR,   /* mtvscr */
-      Pin_AvCMov      /* AV conditional move */
+      Pin_AvCMov,     /* AV conditional move */
+      Pin_Dfp64Unary,   /* DFP64  unary op */
+      Pin_Dfp128nary,   /* DFP128 unary op */
+      Pin_Dfp64Binary,  /* DFP64  binary op */
+      Pin_Dfp128Binary  /* DFP128 binary op */
    }
    PPCInstrTag;
 
@@ -685,6 +694,7 @@ typedef
          /* Load FP Status & Control Register */
          struct {
             HReg src;
+            UInt dfp_rm;
          } FpLdFPSCR;
          /* Do a compare, generating result into an int register. */
          struct {
@@ -782,7 +792,35 @@ typedef
          struct {
             HReg src;
          } AvLdVSCR;
-       } Pin;
+         struct {
+            PPCFpOp op;
+            HReg dst;
+            HReg src;
+         } Dfp64Unary;
+         struct {
+            PPCFpOp op;
+            HReg dst;
+            HReg srcL;
+            HReg srcR;
+         } Dfp64Binary;
+         struct {
+            PPCFpOp op;
+            HReg dst_hi;
+            HReg dst_lo;
+            HReg src_hi;
+            HReg src_lo;
+         } Dfp128Unary;
+         struct {
+            /* The dst is used to pass the left source operand in and return
+             * the result.
+             */
+            PPCFpOp op;
+            HReg dst_hi;
+            HReg dst_lo;
+            HReg srcR_hi;
+            HReg srcR_lo;
+         } Dfp128Binary;
+      } Pin;
    }
    PPCInstr;
 
@@ -820,7 +858,7 @@ extern PPCInstr* PPCInstr_FpRSP      ( HReg dst, HReg src );
 extern PPCInstr* PPCInstr_FpCftI     ( Bool fromI, Bool int32, Bool syned,
                                        Bool dst64, HReg dst, HReg src );
 extern PPCInstr* PPCInstr_FpCMov     ( PPCCondCode, HReg dst, HReg src );
-extern PPCInstr* PPCInstr_FpLdFPSCR  ( HReg src );
+extern PPCInstr* PPCInstr_FpLdFPSCR  ( HReg src, Bool dfp_rm );
 extern PPCInstr* PPCInstr_FpCmp      ( HReg dst, HReg srcL, HReg srcR );
 
 extern PPCInstr* PPCInstr_RdWrLR     ( Bool wrLR, HReg gpr );
@@ -840,7 +878,14 @@ extern PPCInstr* PPCInstr_AvSplat    ( UChar sz, HReg dst, PPCVI5s* src );
 extern PPCInstr* PPCInstr_AvCMov     ( PPCCondCode, HReg dst, HReg src );
 extern PPCInstr* PPCInstr_AvLdVSCR   ( HReg src );
 
-extern void ppPPCInstr ( PPCInstr*, Bool mode64 );
+extern PPCInstr* PPCInstr_Dfp64Unary  ( PPCFpOp op, HReg dst, HReg src );
+extern PPCInstr* PPCInstr_Dfp64Binary ( PPCFpOp op, HReg dst, HReg srcL,
+                                        HReg srcR );
+extern PPCInstr* PPCInstr_Dfp128Binary( PPCFpOp op, HReg dst_hi, HReg dst_lo,
+                                        HReg srcR_hi, HReg srcR_lo );
+
+extern void ppPPCInstr(PPCInstr*, Bool mode64);
+
 
 /* Some functions that insulate the register allocator from details
    of the underlying instruction set. */
index 07b5854c10c3a2dbbe0ef66a05b95f5a2fb32896..78b2a08b589c42f3d35f7c51db6a3b3a44b609fb 100644 (file)
@@ -252,13 +252,15 @@ static IRExpr* bind ( Int binder )
  
 typedef
    struct {
-      IRTypeEnv*   type_env;
-      HReg*        vregmap;
-      HReg*        vregmapHI;
-      Int          n_vregmap;
-      HReg         savedLR;
+      IRTypeEnv* type_env;
+                              //    64-bit mode              32-bit mode
+      HReg*    vregmapLo;     // Low 64-bits [63:0]    Low 32-bits     [31:0]
+      HReg*    vregmapMedLo;  // high 64-bits[127:64]  Next 32-bits    [63:32]
+      HReg*    vregmapMedHi;  // unused                Next 32-bits    [95:64]
+      HReg*    vregmapHi;     // unused                highest 32-bits [127:96]
+      Int      n_vregmap;
+
+      HReg     savedLR;
 
       HInstrArray* code;
  
@@ -280,18 +282,31 @@ static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
 {
    vassert(tmp >= 0);
    vassert(tmp < env->n_vregmap);
-   return env->vregmap[tmp];
+   return env->vregmapLo[tmp];
 }
 
 static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO,
                                ISelEnv* env, IRTemp tmp )
+{
+   vassert(tmp >= 0);
+   vassert(tmp < env->n_vregmap);
+   vassert(env->vregmapMedLo[tmp] != INVALID_HREG);
+   *vrLO = env->vregmapLo[tmp];
+   *vrHI = env->vregmapMedLo[tmp];
+}
+
+/* Only for used in 32-bit mode */
+static void lookupIRTempQuad ( HReg* vrHi, HReg* vrMedHi, HReg* vrMedLo,
+                               HReg* vrLo, ISelEnv* env, IRTemp tmp )
 {
    vassert(!env->mode64);
    vassert(tmp >= 0);
    vassert(tmp < env->n_vregmap);
-   vassert(env->vregmapHI[tmp] != INVALID_HREG);
-   *vrLO = env->vregmap[tmp];
-   *vrHI = env->vregmapHI[tmp];
+   vassert(env->vregmapMedLo[tmp] != INVALID_HREG);
+   *vrHi    = env->vregmapHi[tmp];
+   *vrMedHi = env->vregmapMedHi[tmp];
+   *vrMedLo = env->vregmapMedLo[tmp];
+   *vrLo    = env->vregmapLo[tmp];
 }
 
 static void addInstr ( ISelEnv* env, PPCInstr* instr )
@@ -391,6 +406,14 @@ static PPCRH*        iselWordExpr_RH6u     ( ISelEnv* env, IRExpr* e );
 static PPCAMode*     iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy );
 static PPCAMode*     iselWordExpr_AMode     ( ISelEnv* env, IRExpr* e, IRType xferTy );
 
+static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
+                                         HReg* rMedLo, HReg* rLo,
+                                         ISelEnv* env, IRExpr* e );
+static void iselInt128Expr_to_32x4     ( HReg* rHi, HReg* rMedHi,
+                                         HReg* rMedLo, HReg* rLo,
+                                         ISelEnv* env, IRExpr* e );
+
+
 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */
 static void          iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, 
                                          ISelEnv* env, IRExpr* e );
@@ -415,6 +438,15 @@ static HReg          iselFltExpr     ( ISelEnv* env, IRExpr* e );
 static HReg          iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );
 static HReg          iselVecExpr     ( ISelEnv* env, IRExpr* e );
 
+/* 64-bit mode ONLY. */
+static HReg          iselDfp64Expr_wrk ( ISelEnv* env, IRExpr* e );
+static HReg          iselDfp64Expr     ( ISelEnv* env, IRExpr* e );
+
+/* 64-bit mode ONLY: compute an D128 into a GPR64 pair. */
+static void iselDfp128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env,
+                                 IRExpr* e );
+static void iselDfp128Expr     ( HReg* rHi, HReg* rLo, ISelEnv* env,
+                                 IRExpr* e );
 
 /*---------------------------------------------------------*/
 /*--- ISEL: Misc helpers                                ---*/
@@ -888,15 +920,21 @@ void doHelperCall ( ISelEnv* env,
 static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
 {
    /* 
-   rounding mode | PPC | IR
-   ------------------------
-   to nearest    | 00  | 00
-   to zero       | 01  | 11
-   to +infinity  | 10  | 10
-   to -infinity  | 11  | 01
+   rounding mode                     | PPC  |  IR
+   -----------------------------------------------
+   to nearest, ties to even          | 000  | 000
+   to zero                           | 001  | 011
+   to +infinity                      | 010  | 010
+   to -infinity                      | 011  | 001
+   +++++ Below are the extended rounding modes for decimal floating point +++++
+   to nearest, ties away from 0      | 100  | 100
+   to nearest, ties toward 0         | 101  | 111
+   to away from 0                    | 110  | 110
+   to prepare for shorter precision  | 111  | 101
    */
    HReg r_rmPPC = newVRegI(env);
    HReg r_tmp1  = newVRegI(env);
+   HReg r_tmp2  = newVRegI(env);
 
    vassert(hregClass(r_rmIR) == HRcGPR(env->mode64));
 
@@ -909,20 +947,22 @@ static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
    addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
                                r_tmp1, r_rmIR, PPCRH_Imm(False,1)));
 
-   addInstr(env, PPCInstr_Alu( Palu_XOR, r_tmp1, r_rmIR,
-                               PPCRH_Reg(r_tmp1) ));
+   addInstr( env, PPCInstr_Alu( Palu_AND,
+                                r_tmp2, r_tmp1, PPCRH_Imm( False, 3 ) ) );
 
-   addInstr(env, PPCInstr_Alu( Palu_AND, r_rmPPC, r_tmp1,
-                               PPCRH_Imm(False,3) ));
+   addInstr( env, PPCInstr_Alu( Palu_XOR,
+                                r_rmPPC, r_rmIR, PPCRH_Reg( r_tmp2 ) ) );
 
    return r_rmPPC;
 }
 
 
 /* Set the FPU's rounding mode: 'mode' is an I32-typed expression
-   denoting a value in the range 0 .. 3, indicating a round mode
+   denoting a value in the range 0 .. 7, indicating a round mode
    encoded as per type IRRoundingMode.  Set the PPC FPSCR to have the
-   same rounding.
+   same rounding.  When the dfp_rm arg is True, set the decimal
+   floating point rounding mode bits (29:31); otherwise, set the
+   binary floating point rounding mode bits (62:63).
 
    For speed & simplicity, we're setting the *entire* FPSCR here.
 
@@ -947,7 +987,7 @@ static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
    on any block with any sign of floating point activity.
 */
 static
-void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
+void _set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode, Bool dfp_rm )
 {
    HReg fr_src = newVRegF(env);
    HReg r_src;
@@ -972,15 +1012,40 @@ void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
 
    // Resolve rounding mode and convert to PPC representation
    r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode) );
+
    // gpr -> fpr
    if (env->mode64) {
-      fr_src = mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
+      if (dfp_rm) {
+         HReg r_tmp1 = newVRegI( env );
+         addInstr( env,
+                   PPCInstr_Shft( Pshft_SHL, False/*64bit shift*/,
+                                  r_tmp1, r_src, PPCRH_Imm( False, 32 ) ) );
+         fr_src = mk_LoadR64toFPR( env, r_tmp1 );
+      } else {
+         fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
+      }
    } else {
-      fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
+      if (dfp_rm) {
+         HReg r_zero = newVRegI( env );
+         addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
+         fr_src = mk_LoadRR32toFPR( env, r_src, r_zero );
+      } else {
+         fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
+      }
    }
 
    // Move to FPSCR
-   addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
+   addInstr(env, PPCInstr_FpLdFPSCR( fr_src, dfp_rm ));
+}
+
+static void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
+{
+   _set_FPU_rounding_mode(env, mode, False);
+}
+
+static void set_FPU_DFP_rounding_mode ( ISelEnv* env, IRExpr* mode )
+{
+   _set_FPU_rounding_mode(env, mode, True);
 }
 
 
@@ -2569,7 +2634,6 @@ static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
          *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
          *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
          return;
-
       default: 
          break;
       }
@@ -2594,6 +2658,57 @@ static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
 /*--- ISEL: Integer expressions (64 bit)                ---*/
 /*---------------------------------------------------------*/
 
+/* 32-bit mode ONLY: compute a 128-bit value into a register quad */
+static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo,
+                                     HReg* rLo, ISelEnv* env, IRExpr* e )
+{
+   vassert(!env->mode64);
+   iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e);
+#  if 0
+   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
+#  endif
+   vassert(hregClass(*rHi) == HRcInt32);
+   vassert(hregIsVirtual(*rHi));
+   vassert(hregClass(*rMedHi) == HRcInt32);
+   vassert(hregIsVirtual(*rMedHi));
+   vassert(hregClass(*rMedLo) == HRcInt32);
+   vassert(hregIsVirtual(*rMedLo));
+   vassert(hregClass(*rLo) == HRcInt32);
+   vassert(hregIsVirtual(*rLo));
+}
+
+static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
+                                         HReg* rMedLo, HReg* rLo,
+                                         ISelEnv* env, IRExpr* e )
+{
+   vassert(e);
+   vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
+
+   /* read 128-bit IRTemp */
+   if (e->tag == Iex_RdTmp) {
+      lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp);
+      return;
+   }
+
+   if (e->tag == Iex_Binop) {
+
+      IROp op_binop = e->Iex.Binop.op;
+      switch (op_binop) {
+      case Iop_64HLto128:
+         iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1);
+         iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2);
+         return;
+      default:
+         vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
+                    op_binop);
+         break;
+      }
+   } 
+
+   vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
+   return;
+}
+
 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
    which is returned as the first two parameters.  As with
    iselIntExpr_R, these may be either real or virtual regs; in any
@@ -2864,6 +2979,36 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
          return;
       }
 
+      case Iop_128to64: {
+         /* Narrow, return the low 64-bit half as a 32-bit
+          * register pair */
+         HReg r_Hi    = INVALID_HREG;
+         HReg r_MedHi = INVALID_HREG;
+         HReg r_MedLo = INVALID_HREG;
+         HReg r_Lo    = INVALID_HREG;
+
+         iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
+                                env, e->Iex.Unop.arg);
+         *rHi = r_MedLo;
+         *rLo = r_Lo;
+         return;
+      }
+
+      case Iop_128HIto64: {
+         /* Narrow, return the high 64-bit half as a 32-bit
+          *  register pair */
+         HReg r_Hi    = INVALID_HREG;
+         HReg r_MedHi = INVALID_HREG;
+         HReg r_MedLo = INVALID_HREG;
+         HReg r_Lo    = INVALID_HREG;
+
+         iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
+                                env, e->Iex.Unop.arg);
+         *rHi = r_Hi;
+         *rLo = r_MedHi;
+         return;
+      }
+
       /* V128{HI}to64 */
       case Iop_V128HIto64:
       case Iop_V128to64: {
@@ -3436,6 +3581,173 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
    vpanic("iselDblExpr_wrk(ppc)");
 }
 
+static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e)
+{
+   HReg r = iselDfp64Expr_wrk( env, e );
+   vassert(hregClass(r) == HRcFlt64);
+   vassert( hregIsVirtual(r) );
+   return r;
+}
+
+/* DO NOT CALL THIS DIRECTLY */
+static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e)
+{
+   Bool mode64 = env->mode64;
+   IRType ty = typeOfIRExpr( env->type_env, e );
+   HReg r_dstHi, r_dstLo;
+
+   vassert( e );
+   vassert( ty == Ity_D64 );
+
+   if (e->tag == Iex_RdTmp) {
+      return lookupIRTemp( env, e->Iex.RdTmp.tmp );
+   }
+
+   /* --------- GET --------- */
+   if (e->tag == Iex_Get) {
+      HReg r_dst = newVRegF( env );
+      PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
+                                       GuestStatePtr(mode64) );
+      addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
+      return r_dst;
+   }
+
+   /* --------- OPS --------- */
+   if (e->tag == Iex_Qop) {
+      HReg r_dst = newVRegF( env );
+      return r_dst;
+   }
+
+   if (e->tag == Iex_Unop) {
+      switch (e->Iex.Unop.op) {
+      case Iop_D128HItoD64:
+         iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg );
+         return r_dstHi;
+      case Iop_D128LOtoD64:
+         iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg );
+         return r_dstLo;
+      default:
+         vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
+                     e->Iex.Unop.op );
+      }
+   }
+
+   if (e->tag == Iex_Triop) {
+      PPCFpOp fpop = Pfp_INVALID;
+
+      switch (e->Iex.Triop.op) {
+      case Iop_AddD64:
+         fpop = Pfp_DFPADD;
+         break;
+      case Iop_SubD64:
+         fpop = Pfp_DFPSUB;
+         break;
+      case Iop_MulD64:
+         fpop = Pfp_DFPMUL;
+         break;
+      case Iop_DivD64:
+         fpop = Pfp_DFPDIV;
+         break;
+      default:
+         break;
+      }
+      if (fpop != Pfp_INVALID) {
+         HReg r_dst = newVRegF( env );
+         HReg r_srcL = iselDfp64Expr( env, e->Iex.Triop.arg2 );
+         HReg r_srcR = iselDfp64Expr( env, e->Iex.Triop.arg3 );
+
+         set_FPU_DFP_rounding_mode( env, e->Iex.Triop.arg1 );
+         addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) );
+         return r_dst;
+      }
+   }
+
+   ppIRExpr( e );
+   vpanic( "iselDfp64Expr_wrk(ppc)" );
+}
+
+static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e)
+{
+   iselDfp128Expr_wrk( rHi, rLo, env, e );
+   vassert( hregIsVirtual(*rHi) );
+   vassert( hregIsVirtual(*rLo) );
+}
+
+/* DO NOT CALL THIS DIRECTLY */
+static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
+{
+   vassert( e );
+   vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 );
+
+   /* read 128-bit IRTemp */
+   if (e->tag == Iex_RdTmp) {
+     //      lookupDfp128IRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
+      lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
+      return;
+   }
+
+   /* --------- OPS --------- */
+   if (e->tag == Iex_Binop) {
+      HReg r_srcHi;
+      HReg r_srcLo;
+
+      switch (e->Iex.Binop.op) {
+      case Iop_D64HLtoD128:
+         r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1 );
+         r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2 );
+         *rHi = r_srcHi;
+         *rLo = r_srcLo;
+         return;
+         break;
+      default:
+         vex_printf( "ERROR: iselD128Expr_wrk, UNKNOWN binop case %d\n",
+                     e->Iex.Binop.op );
+         break;
+      }
+   }
+
+   if (e->tag == Iex_Triop) {
+      PPCFpOp fpop = Pfp_INVALID;
+      switch (e->Iex.Triop.op) {
+      case Iop_AddD128:
+         fpop = Pfp_DFPADDQ;
+         break;
+      case Iop_SubD128:
+         fpop = Pfp_DFPSUBQ;
+         break;
+      case Iop_MulD128:
+         fpop = Pfp_DFPMULQ;
+         break;
+      case Iop_DivD128:
+         fpop = Pfp_DFPDIVQ;
+         break;
+      default:
+         break;
+      }
+
+      if (fpop != Pfp_INVALID) {
+         HReg r_dstHi = newVRegV( env );
+         HReg r_dstLo = newVRegV( env );
+         HReg r_srcRHi = newVRegV( env );
+         HReg r_srcRLo = newVRegV( env );
+
+         /* dst will be used to pass in the left operand and get the result. */
+         iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Triop.arg2 );
+         iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, e->Iex.Triop.arg3 );
+         set_FPU_rounding_mode( env, e->Iex.Triop.arg1 );
+         addInstr( env,
+                   PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
+                                          r_srcRHi, r_srcRLo ) );
+         *rHi = r_dstHi;
+         *rLo = r_dstLo;
+         return;
+      }
+   }
+
+   ppIRExpr( e );
+   vpanic( "iselD128Expr(ppc64)" );
+}
+
 
 /*---------------------------------------------------------*/
 /*--- ISEL: SIMD (Vector) expressions, 128 bit.         ---*/
@@ -3985,6 +4297,13 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
                                         fr_src, am_addr ));
          return;
       }
+      if (ty == Ity_D64) {
+         HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data );
+         PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
+                                          GuestStatePtr(mode64) );
+         addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) );
+         return;
+      }
       break;
    }
       
@@ -4023,6 +4342,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       }
       if (!mode64 && ty == Ity_I64) {
          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
+
          iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
@@ -4037,6 +4357,23 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
          return;
       }
+      if (!mode64 && ty == Ity_I128) {
+         HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo;
+         HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo;
+
+         iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi,
+                                &r_srcMedLo, &r_srcLo,
+                                env, stmt->Ist.WrTmp.data);
+
+         lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo,
+                           &r_dstLo, env, tmp);
+
+         addInstr(env, mk_iMOVds_RR(r_dstHi,    r_srcHi) );
+         addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) );
+         addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) );
+         addInstr(env, mk_iMOVds_RR(r_dstLo,    r_srcLo) );
+         return;
+      }
       if (ty == Ity_I1) {
          PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
          HReg r_dst = lookupIRTemp(env, tmp);
@@ -4061,6 +4398,21 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
          addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
          return;
       }
+      if (ty == Ity_D64) {
+         HReg fr_dst = lookupIRTemp( env, tmp );
+         HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data );
+         addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) );
+         return;
+      }
+      if (ty == Ity_D128) {
+         HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo;
+        //         lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
+         lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
+         iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data );
+         addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
+         addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
+         return;
+      }
       break;
    }
 
@@ -4242,13 +4594,12 @@ static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
 /*---------------------------------------------------------*/
 
 /* Translate an entire BS to ppc code. */
-
 HInstrArray* iselSB_PPC ( IRSB* bb, VexArch      arch_host,
                                     VexArchInfo* archinfo_host,
                                     VexAbiInfo*  vbi )
 {
    Int      i, j;
-   HReg     hreg, hregHI;
+   HReg     hregLo, hregMedLo, hregMedHi, hregHi;
    ISelEnv* env;
    UInt     hwcaps_host = archinfo_host->hwcaps;
    Bool     mode64 = False;
@@ -4284,10 +4635,18 @@ HInstrArray* iselSB_PPC ( IRSB* bb, VexArch      arch_host,
    env->type_env = bb->tyenv;
 
    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
-      change as we go along. */
+    * change as we go along. 
+    *
+    * vregmap2 and vregmap3 are only used in 32 bit mode 
+    * for supporting I128 in 32-bit mode
+    */
    env->n_vregmap = bb->tyenv->types_used;
-   env->vregmap   = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
-   env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+   env->vregmapLo    = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+   env->vregmapMedLo = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+   if (!mode64) {
+      env->vregmapMedHi = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+      env->vregmapHi    = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+   }
 
    /* and finally ... */
    env->hwcaps      = hwcaps_host;
@@ -4298,32 +4657,44 @@ HInstrArray* iselSB_PPC ( IRSB* bb, VexArch      arch_host,
       register. */
    j = 0;
    for (i = 0; i < env->n_vregmap; i++) {
-      hregHI = hreg = INVALID_HREG;
+      hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
       switch (bb->tyenv->types[i]) {
       case Ity_I1:
       case Ity_I8:
       case Ity_I16:
       case Ity_I32:
-         if (mode64) { hreg   = mkHReg(j++, HRcInt64,  True); break;
-         } else {      hreg   = mkHReg(j++, HRcInt32,  True); break;
+         if (mode64) { hregLo    = mkHReg(j++, HRcInt64,  True); break;
+         } else {      hregLo    = mkHReg(j++, HRcInt32,  True); break;
          }
       case Ity_I64:  
-         if (mode64) { hreg   = mkHReg(j++, HRcInt64,  True); break;
-         } else {      hreg   = mkHReg(j++, HRcInt32,  True);
-                       hregHI = mkHReg(j++, HRcInt32,  True); break;
+         if (mode64) { hregLo    = mkHReg(j++, HRcInt64,  True); break;
+         } else {      hregLo    = mkHReg(j++, HRcInt32,  True);
+         hregMedLo = mkHReg(j++, HRcInt32,  True); break;
+         }
+      case Ity_I128:
+         if (mode64) { hregLo    = mkHReg(j++, HRcInt64,  True);
+         hregMedLo = mkHReg(j++, HRcInt64,  True); break;
+         } else {      hregLo    = mkHReg(j++, HRcInt32,  True);
+         hregMedLo = mkHReg(j++, HRcInt32,  True);
+         hregMedHi = mkHReg(j++, HRcInt32,  True);
+         hregHi    = mkHReg(j++, HRcInt32,  True); break;
          }
-      case Ity_I128:   vassert(mode64);
-                       hreg   = mkHReg(j++, HRcInt64,  True);
-                       hregHI = mkHReg(j++, HRcInt64,  True); break;
       case Ity_F32:
-      case Ity_F64:    hreg   = mkHReg(j++, HRcFlt64,  True); break;
-      case Ity_V128:   hreg   = mkHReg(j++, HRcVec128, True); break;
+      case Ity_F64:    hregLo    = mkHReg(j++, HRcFlt64,  True); break;
+      case Ity_V128:   hregLo    = mkHReg(j++, HRcVec128, True); break;
+      case Ity_D64:    hregLo    = mkHReg(j++, HRcFlt64,  True); break;
+      case Ity_D128:   hregLo    = mkHReg(j++, HRcFlt64,  True);
+      hregMedLo = mkHReg(j++, HRcFlt64,  True); break;
       default:
          ppIRType(bb->tyenv->types[i]);
          vpanic("iselBB(ppc): IRTemp type");
       }
-      env->vregmap[i]   = hreg;
-      env->vregmapHI[i] = hregHI;
+      env->vregmapLo[i]    = hregLo;
+      env->vregmapMedLo[i] = hregMedLo;
+      if (!mode64) {
+         env->vregmapMedHi[i] = hregMedHi;
+         env->vregmapHi[i]    = hregHi;
+      }
    }
    env->vreg_ctr = j;
 
index 06708a2d5299f8e9ee2b3050d3162119e4c3ec79..545df8e3ff930693394d87c338f768efd23927dc 100644 (file)
@@ -58,6 +58,9 @@ void ppIRType ( IRType ty )
       case Ity_F64:     vex_printf( "F64");  break;
       case Ity_F128:    vex_printf( "F128"); break;
       case Ity_V128:    vex_printf( "V128"); break;
+      case Ity_D32:     vex_printf( "D32");  break;
+      case Ity_D64:     vex_printf( "D64");  break;
+      case Ity_D128:    vex_printf( "D128"); break;
       default: vex_printf("ty = 0x%x\n", (Int)ty);
                vpanic("ppIRType");
    }
@@ -934,6 +937,18 @@ void ppIROp ( IROp op )
       case Iop_Fixed32UToF32x2_RN: vex_printf("Fixed32UToF32x2_RN"); return;
       case Iop_Fixed32SToF32x2_RN: vex_printf("Fixed32SToF32x2_RN"); return;
 
+      case Iop_AddD64:  vex_printf("AddD64");   return;
+      case Iop_SubD64:  vex_printf("SubD64");   return;
+      case Iop_MulD64:  vex_printf("MulD64");   return;
+      case Iop_DivD64:  vex_printf("DivD64");   return;
+      case Iop_AddD128: vex_printf("AddD128");  return;
+      case Iop_SubD128: vex_printf("SubD128");  return;
+      case Iop_MulD128: vex_printf("MulD128");  return;
+      case Iop_DivD128: vex_printf("DivD128");  return;
+      case Iop_D64HLtoD128: vex_printf("D64HLtoD128");  return;
+      case Iop_D128HItoD64: vex_printf("D128HItoD64");  return;
+      case Iop_D128LOtoD64: vex_printf("D128LOtoD64");  return;
+
       default: vpanic("ppIROp(1)");
    }
 
@@ -2591,6 +2606,25 @@ void typeOfPrimop ( IROp op,
       case Iop_F128toF32: BINARY(ity_RMode,Ity_F128, Ity_F32);
       case Iop_F128toF64: BINARY(ity_RMode,Ity_F128, Ity_F64);
 
+      case Iop_D128HItoD64:
+      case Iop_D128LOtoD64:
+         UNARY(Ity_D128, Ity_D64);
+
+      case Iop_D64HLtoD128:
+         BINARY(Ity_D64,Ity_D64, Ity_D128);
+
+      case Iop_AddD64:
+      case Iop_SubD64:
+      case Iop_MulD64:
+      case Iop_DivD64:
+         TERNARY( ity_RMode, Ity_D64, Ity_D64, Ity_D64 );
+
+      case Iop_AddD128:
+      case Iop_SubD128:
+      case Iop_MulD128:
+      case Iop_DivD128:
+         TERNARY(ity_RMode,Ity_D128,Ity_D128, Ity_D128);
+
       default:
          ppIROp(op);
          vpanic("typeOfPrimop");
@@ -2735,6 +2769,7 @@ Bool isPlausibleIRType ( IRType ty )
       case Ity_I8: case Ity_I16: case Ity_I32: 
       case Ity_I64: case Ity_I128:
       case Ity_F32: case Ity_F64: case Ity_F128:
+      case Ity_D32: case Ity_D64: case Ity_D128:
       case Ity_V128:
          return True;
       default: 
@@ -3602,6 +3637,9 @@ Int sizeofIRType ( IRType ty )
       case Ity_F64:  return 8;
       case Ity_F128: return 16;
       case Ity_V128: return 16;
+      case Ity_D32:  return 4;
+      case Ity_D64:  return 8;
+      case Ity_D128: return 16;
       default: vex_printf("\n"); ppIRType(ty); vex_printf("\n");
                vpanic("sizeofIRType");
    }
index 849648d24c4407db2ec8c7e9029a36102bcabd04..a97ce58917f7b973ecb37144273cf0d3bf530012 100644 (file)
@@ -4818,6 +4818,9 @@ static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
                case Ity_F32: case Ity_F64: case Ity_F128: case Ity_V128:
                   *hasVorFtemps = True;
                   break;
+               case Ity_D32: case Ity_D64: case Ity_D128:
+                  *hasVorFtemps = True;
+                  break;
                default: 
                   goto bad;
             }
index 00b76490e1070b7ea0a107eddb181a05c81772b7..d848029d0988c783c8ecb1e23c71745383592add 100644 (file)
@@ -189,8 +189,11 @@ typedef
       /* 1182 */ UChar guest_CR7_321; /* in [3:1] */
       /* 1183 */ UChar guest_CR7_0;   /* in lsb */
 
-      /* FP Status & Control Register fields */
-      /* 1184 */ UInt guest_FPROUND; // FP Rounding Mode
+      /* FP Status & Control Register fields. Only rounding mode fields are supported. */
+      /* 1184 */ UChar guest_FPROUND; // Binary Floating Point Rounding Mode
+      /* 1185 */ UChar guest_DFPROUND; // Decimal Floating Point Rounding Mode
+      /* 1186 */ UChar pad1;
+      /* 1187 */ UChar pad2;
 
       /* Vector Save/Restore Register */
       /* 1188 */ UInt guest_VRSAVE;
index 631791b3f04dd2c26c1527cee76374aa41a7f4d4..e086c02cfdccd94c6b995689e660d13aaa87c03d 100644 (file)
@@ -227,8 +227,12 @@ typedef
       /* 1322 */ UChar guest_CR7_321; /* in [3:1] */
       /* 1323 */ UChar guest_CR7_0;   /* in lsb */
 
-      /* FP Status & Control Register fields */
-      /* 1324 */ UInt guest_FPROUND; // FP Rounding Mode
+      /* FP Status and  Control Register fields. Only rounding mode fields
+        are supported. */
+      /* 1324 */ UChar guest_FPROUND; // Binary Floating Point Rounding Mode
+      /* 1325 */ UChar guest_DFPROUND; // Decimal Floating Point Rounding Mode
+      /* 1326 */ UChar pad1;
+      /* 1327 */ UChar pad2;
 
       /* Vector Save/Restore Register */
       /* 1328 */ UInt guest_VRSAVE;
index 04c9fa906db74d5834b5a7bf995521e9ca13ce4a..3b4c7f006dfac7ead327f115990ed9dc0ccaa487 100644 (file)
@@ -227,6 +227,9 @@ typedef
       Ity_I128,  /* 128-bit scalar */
       Ity_F32,   /* IEEE 754 float */
       Ity_F64,   /* IEEE 754 double */
+      Ity_D32,   /* 32-bit Decimal floating point */
+      Ity_D64,   /* 64-bit Decimal floating point */
+      Ity_D128,  /* 128-bit Decimal floating point */
       Ity_F128,  /* 128-bit floating point; implementation defined */
       Ity_V128   /* 128-bit SIMD */
    }
@@ -983,6 +986,25 @@ typedef
          See floating-point equiwalents for details. */
       Iop_Recip32x2, Iop_Rsqrte32x2,
 
+      /* ------------------ Decimal Floating Point ------------------ */
+
+      /* ARITHMETIC INSTRUCTIONS   64-bit
+        ----------------------------------
+        IRRoundingModeDFP(I32) X D64 X D64 -> D64
+        Iop_AddD64, Iop_SubD64, Iop_MulD64, Iop_DivD64
+      */
+      Iop_AddD64, Iop_SubD64, Iop_MulD64, Iop_DivD64,
+
+      /* ARITHMETIC INSTRUCTIONS  128-bit
+        ----------------------------------
+        IRRoundingModeDFP(I32) X D128 X D128 -> D128
+        Iop_AddD128, Iop_SubD128, Iop_MulD128, Iop_DivD128
+      */
+      Iop_AddD128, Iop_SubD128, Iop_MulD128, Iop_DivD128,
+
+      /* Support for 128-bit DFP type */
+      Iop_D64HLtoD128, Iop_D128HItoD64, Iop_D128LOtoD64,
+
       /* ------------------ 128-bit SIMD FP. ------------------ */
 
       /* --- 32x4 vector FP --- */
@@ -1301,6 +1323,27 @@ typedef
    }
    IRRoundingMode;
 
+/* DFP encoding of IEEE754 2008 specified rounding modes extends the two bit
+ * binary floating point rounding mode (IRRoundingMode) to three bits.  The 
+ * DFP rounding modes are a super set of the binary rounding modes.  The 
+ * encoding was chosen such that the mapping of the least significant two bits
+ * of the IR to POWER encodings is same.  The upper IR encoding bit is just
+ * a logical OR of the upper rounding mode bit from the POWER encoding.
+ */
+typedef
+   enum { 
+      Irrm_DFP_NEAREST              = 0,  // Round to nearest, ties to even
+      Irrm_DFP_NegINF               = 1,  // Round to negative infinity
+      Irrm_DFP_PosINF               = 2,  // Round to posative infinity
+      Irrm_DFP_ZERO                 = 3,  // Round toward zero
+      Irrm_DFP_NEAREST_TIE_AWAY_0   = 4,  // Round to nearest, ties away from 0
+      Irrm_DFP_PREPARE_SHORTER      = 5,  // Round to prepare for storter 
+                                          // precision
+      Irrm_DFP_AWAY_FROM_ZERO       = 6,  // Round to away from 0
+      Irrm_DFP_NEAREST_TIE_TOWARD_0 = 7   // Round to nearest, ties towards 0
+   }
+   IRRoundingModeDFP;
+
 /* Floating point comparison result values, as created by Iop_CmpF64.
    This is also derived from what IA32 does. */
 typedef