]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix implementation of the DFP integer operands.
authorCarl Love <cel@us.ibm.com>
Tue, 22 Jan 2013 20:25:31 +0000 (20:25 +0000)
committerCarl Love <cel@us.ibm.com>
Tue, 22 Jan 2013 20:25:31 +0000 (20:25 +0000)
The implementation of integer operands doesn't really match the documentation
for the Iop. Take for example Iop_ExtractExpD64. It is documented as
D64 -> I64 but the implementation of the UNARY is defined as
UNARY(Ity_D64, Ity_D64). The result is an integer that is stored in an integer
format in a floating point register. On the IBM s390 however, the architecture
stores the integer value in a general purpose register (GPR) not a floating
point register. This issue exists with the implementation of 11 Iops where the
PPC implementation has either a source or destination whose value is an integer
but the value is stored in a floating point register in an integer format. After
reviewing the PPC implementation with the s390 developer, it was agreed the
cleanest way to fix this is to change the PPC implementation. The BINOP will be
changed to be consistent with the Iop description. This means the PPC
instruction implementation of the PPC instruction in guest_ppc_toIR.c will need
to reinterpret integer source operands as integers which will move the value
from a floating point register to an integer register before calling binop().
The underlying PPC implementation of the unop() for the specific Iop will also
need to change to move the value from the integer register back to the floating
point register so the native instruction can be issued with the integer value
in a floating point register. It was decided that making the changed in PPC,
rather then having the s390 reinterpret integers as DFP and then move the value
back to an integer register, was preferable as it makes the implementation of
the unop(), binops(), triop() consistent with the definition of the Iop.

This patch also includes the needed changes for the vbit tester.  The Iop
definitions in memcheck/tests/vbit-test/util.c had to be updated to be consitent
with the changes in the Iops as documented below.  Also, the function mkLazy3()
in memcheck/mc_translate.c had to be updated to handle the I32 x I8 x I64 -> I64
and I32 x I8 x I128 -> I128 cases.

The specific list of changes are as follows:

Iop name in pub/libvex_ir.h
   documented type
     type of UNARY/BINARY/TERNARY in priv/ir_defs.c
-------------------------------------------------------

Iop_ExtractExpD64
   D64 -> I64
      UNARY(Ity_D64, Ity_D64); (current)
      UNARY(Ity_D64, Ity_I64); (fix)

Iop_ExtractExpD128
   D128 -> I64
       UNARY(Ity_D128, Ity_D64); (current)
       UNARY(Ity_D128, Ity_I64); (fix)

Iop_InsertExpD64
   I64 x I64 -> D64
   I64 x D64 -> D64 (fix definition)
       BINARY(Ity_D64,Ity_D64, Ity_D64); (current)
       BINARY(Ity_I64,Ity_D64, Ity_D64); (fix)

Iop_InsertExpD128
    I64 x I128 -> D128
    I64 x D128 -> D128 (fix definition)
        BINARY(Ity_D64,Ity_D128, Ity_D128); (current)
        BINARY(Ity_I64,Ity_D128, Ity_D128); (fix)

Iop_I64StoD128
    I64S -> D128
        UNARY(Ity_D64, Ity_D128); (current)
        UNARY(Ity_I64, Ity_D128); (fix)

Iop_D64toI64S
    IRRoundingModeDFP(I32) x D64 -> I64
        BINARY(ity_RMode, Ity_D64, Ity_D64) (current)
        BINARY(ity_RMode, Ity_D64, Ity_I64) (fix)

Iop_D128toI64S
    IRRoundingModeDFP(I32) x D128 -> I64
        BINARY(ity_RMode, Ity_D128, Ity_D64); (current)
        BINARY(ity_RMode, Ity_D128, Ity_I64); (fix)

Iop_I64StoD64
    IRRoundingModeDFP(I32) x I64 -> D64
        BINARY(ity_RMode, Ity_D64, Ity_D64); (current)
        BINARY(ity_RMode, Ity_I64, Ity_D64); (fix)

Iop_SignificanceRoundD64
    IRRoundingModeDFP(I32) x I8 x D64 -> D64
        TERNARY(ity_RMode,Ity_D64,Ity_D64, Ity_D64); (current)
        TERNARY(ity_RMode,Ity_I8,Ity_D64, Ity_D64); (fix)

Iop_SignificanceRoundD128
    IRRoundingModeDFP(I32) x I8 x D128 -> D128
         TERNARY(ity_RMode,Ity_D128,Ity_D128, Ity_D128); (current)
         TERNARY(ity_RMode,Ity_I8,Ity_D128, Ity_D128); (fix)

The patch is for bugzilla 311100

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

VEX/priv/guest_ppc_toIR.c
VEX/priv/host_ppc_defs.h
VEX/priv/host_ppc_isel.c
VEX/priv/ir_defs.c
VEX/pub/libvex_ir.h

index cab2a43788885a646bf87190d87168d1576858cd..b31d2baf7d679bbcf0a9f56f2e501d59cad8928c 100644 (file)
@@ -9526,13 +9526,18 @@ static Bool dis_dfp_fmt_conv(UInt theInstr) {
       putDReg32( frS_addr, mkexpr( frS ) );
       break;
    case 0x122: // dctfix
-      DIP( "dctfix%s fr%u,fr%u\n",
-           flag_rC ? ".":"", frS_addr, frB_addr );
-      frB = newTemp( Ity_D64 );
-      frS = newTemp( Ity_D64 );
-      assign( frB, getDReg( frB_addr ) );
-      assign( frS, binop( Iop_D64toI64S, round, mkexpr( frB ) ) );
-      putDReg( frS_addr, mkexpr( frS ) );
+      {
+         IRTemp tmp = newTemp( Ity_I64 );
+
+         DIP( "dctfix%s fr%u,fr%u\n",
+              flag_rC ? ".":"", frS_addr, frB_addr );
+         frB = newTemp( Ity_D64 );
+         frS = newTemp( Ity_D64 );
+         assign( frB, getDReg( frB_addr ) );
+         assign( tmp, binop( Iop_D64toI64S, round, mkexpr( frB ) ) );
+         assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
+         putDReg( frS_addr, mkexpr( frS ) );
+      }
       break;
    case 0x322: // dcffix
       DIP( "dcffix%s fr%u,fr%u\n",
@@ -9540,7 +9545,9 @@ static Bool dis_dfp_fmt_conv(UInt theInstr) {
       frB = newTemp( Ity_D64 );
       frS = newTemp( Ity_D64 );
       assign( frB, getDReg( frB_addr ) );
-      assign( frS, binop( Iop_I64StoD64, round, mkexpr( frB ) ) );
+      assign( frS, binop( Iop_I64StoD64,
+                          round,
+                          unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) ) );
       putDReg( frS_addr, mkexpr( frS ) );
       break;
    }
@@ -9575,11 +9582,16 @@ static Bool dis_dfp_fmt_convq(UInt theInstr) {
       putDReg_pair( frS_addr, mkexpr( frS128 ) );
       break;
    case 0x122: // dctfixq
-      DIP( "dctfixq%s fr%u,fr%u\n",
-           flag_rC ? ".":"", frS_addr, frB_addr );
-      assign( frB128, getDReg_pair( frB_addr ) );
-      assign( frS64, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) );
-      putDReg( frS_addr, mkexpr( frS64 ) );
+      {
+         IRTemp tmp = newTemp( Ity_I64 );
+
+         DIP( "dctfixq%s fr%u,fr%u\n",
+              flag_rC ? ".":"", frS_addr, frB_addr );
+         assign( frB128, getDReg_pair( frB_addr ) );
+         assign( tmp, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) );
+         assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
+         putDReg( frS_addr, mkexpr( frS64 ) );
+      }
       break;
    case 0x302: //drdpq
       DIP( "drdpq%s fr%u,fr%u\n",
@@ -9589,6 +9601,7 @@ static Bool dis_dfp_fmt_convq(UInt theInstr) {
       putDReg( frS_addr, mkexpr( frS64 ) );
       break;
    case 0x322: // dcffixq
+     {
       /* Have to introduce an IOP for this instruction so it will work
        * on POWER 6 because emulating the instruction requires a POWER 7
        * DFP instruction in the emulation code.
@@ -9596,9 +9609,12 @@ static Bool dis_dfp_fmt_convq(UInt theInstr) {
       DIP( "dcffixq%s fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frB_addr );
       assign( frB64, getDReg( frB_addr ) );
-      assign( frS128, unop( Iop_I64StoD128, mkexpr( frB64 ) ) );
+      assign( frS128, unop( Iop_I64StoD128,
+                            unop( Iop_ReinterpD64asI64,
+                                  mkexpr( frB64 ) ) ) );
       putDReg_pair( frS_addr, mkexpr( frS128 ) );
       break;
+     }
    }
 
    if (flag_rC && clear_CR1) {
@@ -9630,6 +9646,10 @@ static Bool dis_dfp_round( UInt theInstr ) {
       DIP( "drintx/drintn%s fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frB_addr );
 
+      /* NOTE, this instruction takes a DFP value and rounds to the
+       * neares floating point integer value, i.e. fractional part
+       * is zero.  The result is a floating point number.
+       */
       /* pass the value of R and RMC in the same field */
       assign( frB, getDReg( frB_addr ) );
       assign( frS, binop( Iop_RoundD64toInt,
@@ -9711,7 +9731,7 @@ static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
    case 0x43: // dquai
       DIP( "dquai%s fr%u,fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
-      IRTemp TE_D64 = newTemp( Ity_D64 );
+      IRTemp TE_I64 = newTemp( Ity_I64 );
 
       /* Generate a reference DFP value frA with the desired exponent
        * given by TE using significand from frB.  Need to add the bias
@@ -9721,20 +9741,21 @@ static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
          /* Take 2's complement of the 5-bit value and subtract from bias. 
           *  Bias is adjusted for the +1 required when taking 2's complement.
           */
-         assign( TE_D64,
-                 unop( Iop_ReinterpI64asD64,
-                       binop( Iop_Sub64, mkU64( 397 ),
-                              binop( Iop_And64, mkU64( 0xF ),
-                                     unop( Iop_Not64, mkU64( TE_value ) )
-                                           ) ) ) );
+         assign( TE_I64,
+                 unop( Iop_32Uto64,
+                       binop( Iop_Sub32, mkU32( 397 ),
+                              binop( Iop_And32, mkU32( 0xF ),
+                                     unop( Iop_Not32, mkU32( TE_value ) )
+                                     ) ) ) );
 
       } else {
-         assign( TE_D64,
-                 unop( Iop_ReinterpI64asD64,
-                       binop( Iop_Add64, mkU64( 398 ), mkU64( TE_value ) ) ) );
+          assign( TE_I64,
+                  unop( Iop_32Uto64,
+                        binop( Iop_Add32, mkU32( 398 ), mkU32( TE_value ) )
+                        ) );
       }
 
-      assign( frA, binop( Iop_InsertExpD64, mkexpr( TE_D64 ), 
+      assign( frA, binop( Iop_InsertExpD64, mkexpr( TE_I64 ),
                           unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) );
 
       assign( frS, triop( Iop_QuantizeD64,
@@ -9753,13 +9774,22 @@ static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
                           mkexpr( frB ) ) );
       break;
    case 0x23: // drrnd
-      DIP( "drrnd%s fr%u,fr%u,fr%u\n",
-           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
-      assign( frA, getDReg( frA_addr ) );
-      assign( frS, triop( Iop_SignificanceRoundD64,
-                          mkU32( RMC ),
-                          mkexpr( frA ),
-                          mkexpr( frB ) ) );
+      {
+         IRTemp tmp = newTemp( Ity_I8 );
+
+         DIP( "drrnd%s fr%u,fr%u,fr%u\n",
+              flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+         assign( frA, getDReg( frA_addr ) );
+         /* Iop_64to8 not supported in 32 bit mode, do it in two steps. */
+         assign( tmp, unop( Iop_32to8,
+                            unop( Iop_64to32,
+                                  unop( Iop_ReinterpD64asI64,
+                                        mkexpr( frA ) ) ) ) );
+         assign( frS, triop( Iop_SignificanceRoundD64,
+                             mkU32( RMC ),
+                             mkexpr( tmp ),
+                             mkexpr( frB ) ) );
+      }
       break;
    default:
       vex_printf("dis_dfp_quantize_sig_rrnd(ppc)(opc2)\n");
@@ -9795,7 +9825,7 @@ static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
    case 0x43: // dquaiq
       DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
-      IRTemp TE_D64 = newTemp( Ity_D64 );
+      IRTemp TE_I64 = newTemp( Ity_I64 );
 
       /* Generate a reference DFP value frA with the desired exponent
        * given by TE using significand of 1.  Need to add the bias
@@ -9805,23 +9835,24 @@ static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
          /* Take 2's complement of the 5-bit value and subtract from bias. 
           *  Bias adjusted for the +1 required when taking 2's complement.
           */
-         assign( TE_D64,
-                 unop( Iop_ReinterpI64asD64,
-                       binop( Iop_Sub64, mkU64( 6175 ),
-                              binop( Iop_And64, mkU64( 0xF ),
-                                     unop( Iop_Not64, mkU64( TE_value ) )
-                                           ) ) ) );
+         assign( TE_I64,
+                 unop( Iop_32Uto64,
+                       binop( Iop_Sub32, mkU32( 6175 ),
+                              binop( Iop_And32, mkU32( 0xF ),
+                                     unop( Iop_Not32, mkU32( TE_value ) )
+                                     ) ) ) );
 
       } else {
-         assign( TE_D64,
-                 unop( Iop_ReinterpI64asD64,
-                       binop( Iop_Add64, mkU64( 6176 ), mkU64( TE_value ) )
-                            ) );
+         assign( TE_I64,
+                 unop( Iop_32Uto64,
+                       binop( Iop_Add32,
+                             mkU32( 6176 ),
+                             mkU32( TE_value ) ) ) );
       }
 
       assign( frA,
-              binop( Iop_InsertExpD128, mkexpr( TE_D64 ),
-                     unop( Iop_D64toD128, 
+              binop( Iop_InsertExpD128, mkexpr( TE_I64 ),
+                     unop( Iop_D64toD128,
                            unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) ) );
       assign( frS, triop( Iop_QuantizeD128,
                           mkU32( RMC ),
@@ -9838,13 +9869,22 @@ static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
                           mkexpr( frB ) ) );
       break;
    case 0x23: // drrndq
-      DIP( "drrndq%s fr%u,fr%u,fr%u\n",
-           flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
-      assign( frA, getDReg_pair( frA_addr ) );
-      assign( frS, triop( Iop_SignificanceRoundD128,
-                          mkU32( RMC ),
-                          mkexpr( frA ),
-                          mkexpr( frB ) ) );
+      {
+         IRTemp tmp = newTemp( Ity_I8 );
+
+         DIP( "drrndq%s fr%u,fr%u,fr%u\n",
+              flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
+         assign( frA, getDReg_pair( frA_addr ) );
+         assign( tmp, unop( Iop_32to8,
+                            unop( Iop_64to32,
+                                  unop( Iop_ReinterpD64asI64,
+                                        unop( Iop_D128HItoD64,
+                                              mkexpr( frA ) ) ) ) ) );
+         assign( frS, triop( Iop_SignificanceRoundD128,
+                             mkU32( RMC ),
+                             mkexpr( tmp ),
+                             mkexpr( frB ) ) );
+      }
       break;
    default:
       vex_printf("dis_dfp_quantize_sig_rrndq(ppc)(opc2)\n");
@@ -9871,6 +9911,7 @@ static Bool dis_dfp_extract_insert(UInt theInstr) {
    IRTemp frA = newTemp( Ity_D64 );
    IRTemp frB = newTemp( Ity_D64 );
    IRTemp frS = newTemp( Ity_D64 );
+   IRTemp tmp = newTemp( Ity_I64 );
 
    assign( frA, getDReg( frA_addr ) );
    assign( frB, getDReg( frB_addr ) );
@@ -9879,12 +9920,16 @@ static Bool dis_dfp_extract_insert(UInt theInstr) {
    case 0x162: // dxex
       DIP( "dxex%s fr%u,fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
-      assign( frS, unop( Iop_ExtractExpD64, mkexpr( frB ) ) );
+      assign( tmp, unop( Iop_ExtractExpD64, mkexpr( frB ) ) );
+      assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
       break;
    case 0x362: // diex
       DIP( "diex%s fr%u,fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
-      assign( frS, binop( Iop_InsertExpD64, mkexpr( frA ), mkexpr( frB ) ) );
+      assign( frS, binop( Iop_InsertExpD64,
+                          unop( Iop_ReinterpD64asI64,
+                                mkexpr( frA ) ),
+                          mkexpr( frB ) ) );
       break;
    default:
       vex_printf("dis_dfp_extract_insert(ppc)(opc2)\n");
@@ -9912,6 +9957,7 @@ static Bool dis_dfp_extract_insertq(UInt theInstr) {
    IRTemp frB   = newTemp( Ity_D128 );
    IRTemp frS64 = newTemp( Ity_D64 );
    IRTemp frS   = newTemp( Ity_D128 );
+   IRTemp tmp   = newTemp( Ity_I64 );
    Bool clear_CR1 = True;
 
    assign( frB, getDReg_pair( frB_addr ) );
@@ -9924,14 +9970,17 @@ static Bool dis_dfp_extract_insertq(UInt theInstr) {
        * consistent and not have to add a new struct, the emulation returns
        * the 64-bit result in the upper and lower register.
        */
-      assign( frS64, unop( Iop_ExtractExpD128, mkexpr( frB ) ) );
+      assign( tmp, unop( Iop_ExtractExpD128, mkexpr( frB ) ) );
+      assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
       putDReg( frS_addr, mkexpr( frS64 ) );
       break;
    case 0x362:  // diexq
       DIP( "diexq%s fr%u,fr%u,fr%u\n",
            flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
       assign( frA, getDReg( frA_addr ) );
-      assign( frS, binop( Iop_InsertExpD128, mkexpr( frA ), mkexpr( frB ) ) );
+      assign( frS, binop( Iop_InsertExpD128,
+                          unop( Iop_ReinterpD64asI64, mkexpr( frA ) ),
+                          mkexpr( frB ) ) );
       putDReg_pair( frS_addr, mkexpr( frS ) );
       break;
    default:
@@ -10059,14 +10108,12 @@ static Bool dis_dfp_exponent_test ( UInt theInstr )
       assign( frA, getDReg( frA_addr ) );
       assign( frB, getDReg( frB_addr ) );
       assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
-      assign(exponent_A, unop( Iop_64to32, 
-                               unop( Iop_ReinterpD64asI64,
-                                     unop( Iop_ExtractExpD64,
-                                           mkexpr( frA ) ) ) ) );
-      assign(exponent_B, unop( Iop_64to32, 
-                               unop( Iop_ReinterpD64asI64,
-                                     unop( Iop_ExtractExpD64,
-                                           mkexpr( frB ) ) ) ) );
+      assign(exponent_A, unop( Iop_64to32,
+                               unop( Iop_ExtractExpD64,
+                                     mkexpr( frA ) ) ) );
+      assign(exponent_B, unop( Iop_64to32,
+                               unop( Iop_ExtractExpD64,
+                                     mkexpr( frB ) ) ) );
       break;
 
    case 0x3F: //  dtstexq      Quad instruction setup
@@ -10076,14 +10123,12 @@ static Bool dis_dfp_exponent_test ( UInt theInstr )
       assign( frA, unop( Iop_D128HItoD64, mkexpr( frA128 ) ) );
       assign( frB, unop( Iop_D128HItoD64, mkexpr( frB128 ) ) );
       assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
-      assign( exponent_A, unop( Iop_64to32, 
-                                unop( Iop_ReinterpD64asI64,
-                                      unop( Iop_ExtractExpD128,
-                                            mkexpr( frA128 ) ) ) ) );
-      assign( exponent_B, unop( Iop_64to32, 
-                                unop( Iop_ReinterpD64asI64,
-                                      unop( Iop_ExtractExpD128,
-                                            mkexpr( frB128 ) ) ) ) );
+      assign( exponent_A, unop( Iop_64to32,
+                                unop( Iop_ExtractExpD128,
+                                      mkexpr( frA128 ) ) ) );
+      assign( exponent_B, unop( Iop_64to32,
+                                unop( Iop_ExtractExpD128,
+                                      mkexpr( frB128 ) ) ) );
       break;
    default:
       vex_printf("dis_dfp_exponent_test(ppc)(opc2)\n");
@@ -10236,7 +10281,7 @@ static Bool dis_dfp_class_test ( UInt theInstr )
    IRTemp min_subnormalD128 = newTemp( Ity_D128 );
    IRTemp significand64  = newTemp( Ity_D64 );
    IRTemp significand128 = newTemp( Ity_D128 );
-   IRTemp exp_min_normal = newTemp( Ity_D64 );
+   IRTemp exp_min_normal = newTemp( Ity_I64 );
    IRTemp exponent       = newTemp( Ity_I32 );
 
    IRTemp infinity_true  = newTemp( Ity_I32 );
@@ -10299,15 +10344,13 @@ static Bool dis_dfp_class_test ( UInt theInstr )
       max_exp = DFP_LONG_EXP_MAX;
       min_exp = DFP_LONG_EXP_MIN;
 
-      assign( exponent, unop( Iop_64to32, 
-                              unop( Iop_ReinterpD64asI64,
-                                    unop( Iop_ExtractExpD64,
-                                          mkexpr( frA ) ) ) ) );
+      assign( exponent, unop( Iop_64to32,
+                              unop( Iop_ExtractExpD64,
+                                    mkexpr( frA ) ) ) );
       assign( significand64,
               unop( Iop_ReinterpI64asD64,
                     mkU64( 0x2234000000000001ULL ) ) );  // dfp 1.0
-      assign( exp_min_normal,
-              unop( Iop_ReinterpI64asD64, mkU64( 398 - 383 ) ) );
+      assign( exp_min_normal,mkU64( 398 - 383 ) );
       assign( min_subnormalD64,
               binop( Iop_InsertExpD64,
                      mkexpr( exp_min_normal ),
@@ -10341,13 +10384,11 @@ static Bool dis_dfp_class_test ( UInt theInstr )
       max_exp = DFP_EXTND_EXP_MAX;
       min_exp = DFP_EXTND_EXP_MIN;
       assign( exponent, unop( Iop_64to32, 
-                              unop( Iop_ReinterpD64asI64,
-                                    unop( Iop_ExtractExpD128,
-                                          getDReg_pair( frA_addr) ) ) ) );
+                              unop( Iop_ExtractExpD128,
+                                    getDReg_pair( frA_addr) ) ) );
 
       /* create quand exponent for minimum normal number */
-      assign( exp_min_normal,
-              unop( Iop_ReinterpI64asD64, mkU64( 6176 - 6143 ) ) );
+      assign( exp_min_normal, mkU64( 6176 - 6143 ) );
       assign( significand128,
               unop( Iop_D64toD128,
                     unop( Iop_ReinterpI64asD64,
@@ -10797,8 +10838,7 @@ static Bool dis_dfp_bcd(UInt theInstr) {
          assign( without_lmd,
                  unop( Iop_ReinterpD64asI64,
                        binop( Iop_InsertExpD64,
-                              unop( Iop_ReinterpI64asD64,
-                                    mkU64( DFP_LONG_BIAS ) ),
+                              mkU64( DFP_LONG_BIAS ),
                               unop( Iop_ReinterpI64asD64,
                                     binop( Iop_32HLto64,
                                            mkexpr( dbcd_u ),
@@ -10886,8 +10926,7 @@ static Bool dis_dfp_bcd(UInt theInstr) {
          assign( tmp64,
                  unop( Iop_ReinterpD64asI64,
                        binop( Iop_InsertExpD64,
-                              unop( Iop_ReinterpI64asD64,
-                                    mkU64( DFP_LONG_BIAS ) ),
+                              mkU64( DFP_LONG_BIAS ),
                               unop( Iop_ReinterpI64asD64,
                                     binop( Iop_32HLto64,
                                            binop( Iop_Or32,
@@ -11278,7 +11317,7 @@ static Bool dis_dfp_bcdq( UInt theInstr )
        */
       assign( result128,
               binop( Iop_InsertExpD128,
-                     unop( Iop_ReinterpI64asD64, mkU64( DFP_EXTND_BIAS ) ),
+                     mkU64( DFP_EXTND_BIAS ),
                      mkexpr( dfp_significand ) ) );
 
       assign( tmp_hi,
index b1a567c03e4815b60439d646516a0a69dfb543df..9c2d05de1ec888dfebdbff9d67f86df27f4ac861 100644 (file)
@@ -375,7 +375,7 @@ typedef
       Pfp_ADDD, Pfp_SUBD, Pfp_MULD, Pfp_DIVD,
       Pfp_ADDS, Pfp_SUBS, Pfp_MULS, Pfp_DIVS,
       Pfp_DRSP, Pfp_DRDPQ, Pfp_DCTFIX, Pfp_DCTFIXQ, Pfp_DCFFIX, 
-      Pfp_DQUA, Pfp_RRDTR, Pfp_DIEX, Pfp_DIEXQ, 
+      Pfp_DQUA, Pfp_RRDTR, Pfp_DIEX, Pfp_DIEXQ, Pfp_DRINTN,
 
       /* Unary */
       Pfp_SQRT, Pfp_ABS, Pfp_NEG, Pfp_MOV, Pfp_RES, Pfp_RSQRTE,
index 50dd9b86396ff4c59ab9785ee07922d0f016959c..e379d86250f3f4f0f4a129d82d48bf4d56a59e16 100644 (file)
@@ -1637,6 +1637,46 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          }
       }
 
+      if (e->Iex.Binop.op == Iop_D64toI64S ) {
+         HReg      r1      = StackFramePtr(env->mode64);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
+         HReg      fr_src  = iselDfp64Expr(env, e->Iex.Binop.arg2);
+         HReg      idst    = newVRegI(env);
+         HReg      ftmp    = newVRegF(env);
+
+         /* Set host rounding mode */
+         set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
+         addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, ftmp, fr_src));
+         sub_from_sp( env, 16 );
+         addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
+         addInstr(env, PPCInstr_Load(8, idst, zero_r1, mode64));
+
+         add_to_sp( env, 16 );
+
+         ///* Restore default FPU rounding. */
+         //set_FPU_rounding_default( env );
+         return idst;
+      }
+
+      if (e->Iex.Binop.op == Iop_D128toI64S ) {
+         PPCFpOp fpop = Pfp_DCTFIXQ;
+         HReg r_srcHi = newVRegF(env);
+         HReg r_srcLo = newVRegF(env);
+         HReg idst    = newVRegI(env);
+         HReg ftmp    = newVRegF(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+
+         set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
+         iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2);
+         addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
+
+         // put the D64 result into an integer register
+         sub_from_sp( env, 16 );
+         addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
+         addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
+         add_to_sp( env, 16 );
+         return idst;
+      }
       break;
    }
 
@@ -2070,6 +2110,44 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       default: 
          break;
       }
+
+     switch (e->Iex.Unop.op) {
+        case Iop_ExtractExpD64: {
+
+            HReg fr_dst = newVRegI(env);
+            HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg);
+            HReg tmp    = newVRegF(env);
+            PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+            addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
+
+            // put the D64 result into a integer register
+            sub_from_sp( env, 16 );
+            addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
+            addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
+            add_to_sp( env, 16 );
+            return fr_dst;
+         }
+         case Iop_ExtractExpD128: {
+            HReg fr_dst = newVRegI(env);
+            HReg r_srcHi;
+            HReg r_srcLo;
+            HReg tmp    = newVRegF(env);
+            PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+
+            iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg);
+            addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
+                                                  r_srcHi, r_srcLo));
+
+            sub_from_sp( env, 16 );
+            addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
+            addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
+            add_to_sp( env, 16 );
+            return fr_dst;
+         }
+         default: 
+            break;
+      }
+
       break;
    }
 
@@ -3024,7 +3102,52 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
             *rLo = tLo;
             return;
          }
+         case Iop_D64toI64S: {
+            HReg      tLo     = newVRegI(env);
+            HReg      tHi     = newVRegI(env);
+            HReg      r1      = StackFramePtr(env->mode64);
+            PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
+            PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
+            HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2);
+            HReg tmp    = newVRegF(env);
 
+            vassert(!env->mode64);
+            set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
+            addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src));
+
+            sub_from_sp( env, 16 );
+            addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
+            addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
+            addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
+            add_to_sp( env, 16 );
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
+         case Iop_D128toI64S: {
+            PPCFpOp fpop = Pfp_DCTFIXQ;
+            HReg r_srcHi = newVRegF(env);
+            HReg r_srcLo = newVRegF(env);
+            HReg tLo     = newVRegI(env);
+            HReg tHi     = newVRegI(env);
+            HReg ftmp    = newVRegF(env);
+            PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+            PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+            set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
+            iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2);
+            addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
+
+            // put the D64 result into an integer register pair
+            sub_from_sp( env, 16 );
+            addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
+            addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
+            addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
+            add_to_sp( env, 16 );
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
          default: 
             break;
       }
@@ -3085,6 +3208,49 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
          *rLo = src;
          return;
       }
+      case Iop_ExtractExpD64: {
+         HReg tmp    = newVRegF(env);
+         HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg);
+         HReg      tLo     = newVRegI(env);
+         HReg      tHi     = newVRegI(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+         PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+         addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
+
+         // put the D64 result into a integer register pair
+         sub_from_sp( env, 16 );
+         addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
+         addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
+         addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
+         add_to_sp( env, 16 );
+         *rHi = tHi;
+         *rLo = tLo;
+         return;
+      }
+      case Iop_ExtractExpD128: {
+         HReg      r_srcHi;
+         HReg      r_srcLo;
+         HReg      tmp     = newVRegF(env);
+         HReg      tLo     = newVRegI(env);
+         HReg      tHi     = newVRegI(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+         PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+         iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg);
+         addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
+                                                  r_srcHi, r_srcLo));
+
+         // put the D64 result into a integer register pair
+         sub_from_sp( env, 16 );
+         addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
+         addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
+         addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
+         add_to_sp( env, 16 );
+         *rHi = tHi;
+         *rLo = tLo;
+         return;
+      }
 
       /* 32Uto64(e) */
       case Iop_32Uto64: {
@@ -3628,32 +3794,15 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
          return r_dst;
       }
-      switch (triop->op) {
-      case Iop_QuantizeD64:          fpop = Pfp_DQUA;  break;
-      case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
-      default: break;
-      }
-      if (fpop != Pfp_INVALID) {
-         HReg r_dst = newVRegF(env);
-         HReg r_srcL = iselDblExpr(env, triop->arg2);
-         HReg r_srcR = iselDblExpr(env, triop->arg3);
-         PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1);
-
-         // will set TE and RMC when issuing instruction
-         addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
-         return r_dst;
-      }
    }
 
    if (e->tag == Iex_Binop) {
       PPCFpOp fpop = Pfp_INVALID;
       switch (e->Iex.Binop.op) {
       case Iop_SqrtF64:   fpop = Pfp_SQRT;   break;
-      case Iop_I64StoD64: fpop = Pfp_DCFFIX; break;
-      case Iop_D64toI64S: fpop = Pfp_DCTFIX; break;
       default: break;
       }
-      if (fpop != Pfp_INVALID) {
+      if (fpop == Pfp_SQRT) {
          HReg fr_dst = newVRegF(env);
          HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2);
          set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
@@ -3740,7 +3889,6 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          case Iop_RoundF64toF64_PosINF:  fpop = Pfp_FRIP; break;
          case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
          case Iop_RoundF64toF64_ZERO:    fpop = Pfp_FRIZ; break;
-         case Iop_ExtractExpD64:         fpop = Pfp_DXEX; break;
          default: break;
       }
       if (fpop != Pfp_INVALID) {
@@ -3936,23 +4084,6 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e)
             return mk_LoadR64toFPR( env, r_src );
          }
       }
-
-      case Iop_ExtractExpD64: {
-         HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg);
-
-         addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, fr_dst, fr_src));
-         return fr_dst;
-      }
-      case Iop_ExtractExpD128: {
-         /* Result is a D64 */
-         HReg r_srcHi;
-         HReg r_srcLo;
-
-         iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg);
-         addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, fr_dst,
-                                              r_srcHi, r_srcLo));
-         return fr_dst;
-      }
       case Iop_D32toD64: {
          HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg);
          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src));
@@ -3979,22 +4110,17 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e)
    }
 
    if (e->tag == Iex_Binop) {
+      PPCFpOp fpop = Pfp_INVALID;
+      HReg fr_dst = newVRegF(env);
 
       switch (e->Iex.Binop.op) {
-      case Iop_D128toI64S: {
-         PPCFpOp fpop = Pfp_DCTFIXQ;
-         HReg fr_dst  = newVRegF(env);
-         HReg r_srcHi = newVRegF(env);
-         HReg r_srcLo = newVRegF(env);
-
-         set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
-         iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2);
-         addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
-         return fr_dst;
+      case Iop_D128toD64:     fpop = Pfp_DRDPQ;  break;
+      case Iop_D64toD32:      fpop = Pfp_DRSP;   break;
+      case Iop_I64StoD64:     fpop = Pfp_DCFFIX; break;
+      case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break;
+      default: break;
       }
-      case Iop_D128toD64: {
-         PPCFpOp fpop = Pfp_DRDPQ;
-         HReg fr_dst  = newVRegF(env);
+      if (fpop == Pfp_DRDPQ) {
          HReg r_srcHi = newVRegF(env);
          HReg r_srcLo = newVRegF(env);
 
@@ -4002,37 +4128,65 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e)
          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2);
          addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
          return fr_dst;
-      }
-      break;
-      default:
-         break;
-      }
 
-      if (e->Iex.Unop.op == Iop_RoundD64toInt) {
-         HReg fr_dst = newVRegF(env);
+      } else if (fpop == Pfp_DRINTN) {
          HReg fr_src = newVRegF(env);
          PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1);
 
+         /* NOTE, this IOP takes a DFP value and rounds to the
+          * neares floating point integer value, i.e. fractional part
+          * is zero.  The result is a decimal floating point number.
+          * the INT in the name is a bit misleading.
+          */
          fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2);
          addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc));
          return fr_dst;
-      }
-   }
 
-   if (e->tag == Iex_Binop) {
-      PPCFpOp fpop = Pfp_INVALID;
-      HReg fr_dst = newVRegF(env);
-
-      switch (e->Iex.Binop.op) {
-      case Iop_I64StoD64:    fpop = Pfp_DCFFIX; break;
-      case Iop_D64toI64S:    fpop = Pfp_DCTFIX; break;
-      default: break;
-      }
-      if (fpop != Pfp_INVALID) {
+      } else if (fpop == Pfp_DRSP) {
          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2);
          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
          addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
          return fr_dst;
+
+      } else if (fpop == Pfp_DCFFIX) {
+         HReg fr_src = newVRegF(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+
+         set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
+         sub_from_sp( env, 16 );
+
+         // put the I64 value into a floating point register
+         if (mode64) {
+            HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+           addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
+         } else {
+            HReg tmpHi, tmpLo;
+            PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+            iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2);
+            addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
+            addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
+         }
+
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8,  fr_src, zero_r1));
+         addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
+         add_to_sp( env, 16 );
+         return fr_dst;
+
+      } else if (fpop == Pfp_DCTFIX) {
+         HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2);
+         HReg tmp    = newVRegI(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+
+         set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 );
+         addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
+
+         sub_from_sp( env, 16 );
+         addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, fr_dst, zero_r1));
+         addInstr(env, PPCInstr_Load(8, tmp, zero_r1, env->mode64));
+         add_to_sp( env, 16 );
+         return tmp;
       }
 
       switch (e->Iex.Binop.op) {
@@ -4059,9 +4213,30 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e)
       default:         break;
       }
       if (fpop != Pfp_INVALID) {
-         HReg fr_srcL = iselDfp64Expr(env, e->Iex.Binop.arg1);
+         HReg fr_srcL = newVRegF(env);
          HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2);
-         addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL, fr_srcR));
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+         sub_from_sp( env, 16 );
+
+         if (env->mode64) {
+            // put the I64 value into a floating point reg
+            HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1);
+
+            addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
+         } else {
+            // put the I64 register pair into a floating point reg
+            HReg tmpHi;
+            HReg tmpLo;
+            PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+            iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1);
+            addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/));
+            addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/));
+         }
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1));
+         addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL,
+                                            fr_srcR));
+         add_to_sp( env, 16 );
          return fr_dst;
       }
    }
@@ -4101,15 +4276,36 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e)
       case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
       default: break;
       }
-      if (fpop != Pfp_INVALID) {
+      if (fpop == Pfp_DQUA) {
          HReg r_dst = newVRegF(env);
          HReg r_srcL = iselDfp64Expr(env, triop->arg2);
          HReg r_srcR = iselDfp64Expr(env, triop->arg3);
          PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1);
-
          addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR,
                                             rmc));
          return r_dst;
+
+      } else if (fpop == Pfp_RRDTR) {
+         HReg r_dst = newVRegF(env);
+         HReg r_srcL = newVRegF(env);
+         HReg r_srcR = iselDfp64Expr(env, triop->arg3);
+         PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+         HReg i8_val = iselWordExpr_R(env, triop->arg2);
+
+         /* Move I8 to float register to issue instruction */
+         sub_from_sp( env, 16 );
+         if (mode64)
+            addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
+         else
+            addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/));
+
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
+         add_to_sp( env, 16 );
+
+         // will set TE and RMC when issuing instruction
+         addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
+         return r_dst;
       }
    }
 
@@ -4137,26 +4333,39 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
    }
 
    if (e->tag == Iex_Unop) {
-      PPCFpOp fpop = Pfp_INVALID;
       HReg r_dstHi = newVRegF(env);
       HReg r_dstLo = newVRegF(env);
 
       if (e->Iex.Unop.op == Iop_I64StoD128) {
-         HReg r_src   = iselDfp64Expr(env, e->Iex.Unop.arg);
-         fpop = Pfp_DCFFIXQ;
+         HReg fr_src = newVRegF(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+
+         // put the I64 value into a floating point reg
+         if (env->mode64) {
+            HReg tmp   = iselWordExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
+         } else {
+            HReg tmpHi, tmpLo;
+            PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+            iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg);
+            addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
+            addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
+         }
 
-         addInstr(env, PPCInstr_DfpI64StoD128(fpop, r_dstHi, r_dstLo,
-                                              r_src));
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
+         addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo,
+                                              fr_src));
       }
+
       if (e->Iex.Unop.op == Iop_D64toD128) {
-         HReg r_src   = iselDfp64Expr(env, e->Iex.Unop.arg);
-         fpop = Pfp_DCTQPQ;
+         HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg);
 
-         /* Source is 64bit result is 128 bit.  High 64bit source arg,
+         /* Source is 64bit, result is 128 bit.  High 64bit source arg,
           * is ignored by the instruction.  Set high arg to r_src just
           * to meet the vassert tests.
           */
-         addInstr(env, PPCInstr_Dfp128Unary(fpop, r_dstHi, r_dstLo,
+         addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo,
                                             r_src, r_src));
       }
       *rHi = r_dstHi;
@@ -4229,9 +4438,26 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
          HReg r_dstHi = newVRegF(env);
          HReg r_dstLo = newVRegF(env);
          HReg r_srcL  = newVRegF(env);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+         r_srcHi = newVRegF(env);
+         r_srcLo = newVRegF(env);
 
-         r_srcL = iselDfp64Expr(env, e->Iex.Binop.arg1);
          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2);
+
+         /* Move I64 to float register to issue instruction */
+         if (env->mode64) {
+            HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1);
+            addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
+         } else {
+            HReg tmpHi, tmpLo;
+            PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+
+            iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg);
+            addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
+            addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
+         }
+
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
          addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ,
                                               r_dstHi, r_dstLo,
                                               r_srcL, r_srcHi, r_srcLo));
@@ -4249,6 +4475,9 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
    if (e->tag == Iex_Triop) {
       IRTriop *triop = e->Iex.Triop.details;
       PPCFpOp fpop = Pfp_INVALID;
+      HReg r_dstHi = newVRegF(env);
+      HReg r_dstLo = newVRegF(env);
+
       switch (triop->op) {
       case Iop_AddD128:
          fpop = Pfp_DFPADDQ;
@@ -4267,8 +4496,6 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
       }
 
       if (fpop != Pfp_INVALID) {
-         HReg r_dstHi = newVRegV( env );
-         HReg r_dstLo = newVRegV( env );
          HReg r_srcRHi = newVRegV( env );
          HReg r_srcRLo = newVRegV( env );
 
@@ -4288,9 +4515,7 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
       case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
       default: break;
       }
-      if (fpop != Pfp_INVALID) {
-         HReg r_dstHi = newVRegF(env);
-         HReg r_dstLo = newVRegF(env);
+      if (fpop == Pfp_DQUAQ) {
          HReg r_srcHi = newVRegF(env);
          HReg r_srcLo = newVRegF(env);
          PPCRI* rmc = iselWordExpr_RI(env, triop->arg1);
@@ -4299,6 +4524,46 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
          iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2);
          iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3);
 
+         // will set RMC when issuing instruction
+         addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
+                                               r_srcHi, r_srcLo, rmc));
+        *rHi = r_dstHi;
+        *rLo = r_dstLo;
+         return;
+
+      } else if (fpop == Pfp_DRRNDQ) {
+         HReg r_srcHi = newVRegF(env);
+         HReg r_srcLo = newVRegF(env);
+         PPCRI* rmc = iselWordExpr_RI(env, triop->arg1);
+         PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+         PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
+         HReg i8_val = iselWordExpr_R(env, triop->arg2);
+         HReg r_zero = newVRegI( env );
+
+         iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3);
+
+         /* dst will be used to pass in the left operand and get the result */
+         /* Move I8 to float register to issue instruction.  Note, the
+          * instruction only looks at the bottom 6 bits so we really don't
+          * have to clear the upper bits since the iselWordExpr_R sets the
+          * bottom 8-bits.
+          */
+         sub_from_sp( env, 16 );
+
+         if (env->mode64)
+            addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
+         else
+            addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/));
+
+         /* Have to write to the upper bits to ensure they have been
+          * initialized. The instruction ignores all but the lower 6-bits.
+          */
+         addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1));
+         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1));
+
+         add_to_sp( env, 16 );
+
          // will set RMC when issuing instruction
          addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
                                                r_srcHi, r_srcLo, rmc));
@@ -4306,7 +4571,7 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
          *rLo = r_dstLo;
          return;
       }
  }
+ }
 
    ppIRExpr( e );
    vpanic( "iselDfp128Expr(ppc64)" );
index d81a37b7e46e9a612919a2dff63052fbd6d8cfa7..3ae2bdac14c15418ef5eb1c471feb7f67441c7da 100644 (file)
@@ -2857,22 +2857,22 @@ void typeOfPrimop ( IROp op,
          UNARY(Ity_D32, Ity_D64);
 
       case Iop_ExtractExpD64:
-         UNARY(Ity_D64, Ity_D64);
+         UNARY(Ity_D64, Ity_I64);
 
       case Iop_ExtractSigD64:
          UNARY(Ity_D64, Ity_I64);
 
       case Iop_InsertExpD64:
-         BINARY(Ity_D64,Ity_D64, Ity_D64);
+         BINARY(Ity_I64,Ity_D64, Ity_D64);
 
       case Iop_ExtractExpD128:
-         UNARY(Ity_D128, Ity_D64);
+         UNARY(Ity_D128, Ity_I64);
 
-     case Iop_ExtractSigD128:
+      case Iop_ExtractSigD128:
         UNARY(Ity_D128, Ity_I64);
 
       case Iop_InsertExpD128:
-         BINARY(Ity_D64,Ity_D128, Ity_D128);
+         BINARY(Ity_I64,Ity_D128, Ity_D128);
 
       case Iop_D64toD128:
          UNARY(Ity_D64, Ity_D128);
@@ -2893,8 +2893,8 @@ void typeOfPrimop ( IROp op,
       case Iop_I32UtoD128:
          UNARY(Ity_I32, Ity_D128);
 
-      case Iop_I64StoD128:    /* I64 bit pattern stored in Float register */
-         UNARY(Ity_D64, Ity_D128);
+      case Iop_I64StoD128:
+         UNARY(Ity_I64, Ity_D128);
 
       case Iop_I64UtoD128:
          UNARY(Ity_I64, Ity_D128);
@@ -2908,7 +2908,7 @@ void typeOfPrimop ( IROp op,
          UNARY(Ity_D128, Ity_D64);
 
       case Iop_D128toI64S:
-         BINARY(ity_RMode, Ity_D128, Ity_D64);
+         BINARY(ity_RMode, Ity_D128, Ity_I64);
 
       case Iop_D128toI64U:
          BINARY(ity_RMode, Ity_D128, Ity_I64);
@@ -2932,7 +2932,7 @@ void typeOfPrimop ( IROp op,
          BINARY(ity_RMode, Ity_D64, Ity_I32);
 
       case Iop_D64toI64S:
-         BINARY(ity_RMode, Ity_D64, Ity_D64);
+         BINARY(ity_RMode, Ity_D64, Ity_I64);
 
       case Iop_D64toI64U:
          BINARY(ity_RMode, Ity_D64, Ity_I64);
@@ -2941,8 +2941,8 @@ void typeOfPrimop ( IROp op,
       case Iop_I32UtoD64:
          UNARY(Ity_I32, Ity_D64);
 
-      case Iop_I64StoD64:  /* I64 bit pattern stored in Float register */
-         BINARY(ity_RMode, Ity_D64, Ity_D64);
+      case Iop_I64StoD64:
+         BINARY(ity_RMode, Ity_I64, Ity_D64);
 
       case Iop_I64UtoD64:
          BINARY(ity_RMode, Ity_I64, Ity_D64);
@@ -2956,13 +2956,17 @@ void typeOfPrimop ( IROp op,
          BINARY(Ity_D128,Ity_D128, Ity_I32);
 
       case Iop_QuantizeD64:
-      case Iop_SignificanceRoundD64:
          TERNARY(ity_RMode,Ity_D64,Ity_D64, Ity_D64);
 
+      case Iop_SignificanceRoundD64:
+         TERNARY(ity_RMode, Ity_I8,Ity_D64, Ity_D64);
+
       case Iop_QuantizeD128:
-      case Iop_SignificanceRoundD128:
          TERNARY(ity_RMode,Ity_D128,Ity_D128, Ity_D128);
 
+      case Iop_SignificanceRoundD128:
+         TERNARY(ity_RMode, Ity_I8,Ity_D128, Ity_D128);
+
       case Iop_ShlD128:
       case Iop_ShrD128:
          BINARY(Ity_D128, Ity_I8, Ity_D128 );
index c132995320b1141493cf894fdca6bece5cd5a281..8b992d365db317ec8d9d8232fcb1f7f842f58fdd 100644 (file)
@@ -1095,7 +1095,8 @@ typedef
 
       /* ROUNDING INSTRUCTIONS
        * IRRoundingMode(I32) x D64 -> D64
-       * The D64 operand, if a finite number, is rounded to an integer value.
+       * The D64 operand, if a finite number, it is rounded to a
+       * floating point integer value, i.e. no fractional part.
        */
       Iop_RoundD64toInt,
 
@@ -1159,7 +1160,7 @@ typedef
       /* D128 -> I64 */
       Iop_ExtractSigD128,
 
-      /* I64 x I64  -> D64 
+      /* I64 x D64  -> D64
        *    The exponent is specified by the first I64 operand the signed
        *    significand is given by the second I64 value.  The result is a D64
        *    value consisting of the specified significand and exponent whose 
@@ -1167,7 +1168,7 @@ typedef
        */
       Iop_InsertExpD64,
 
-      /* I64 x I128 -> D128 */
+      /* I64 x D128 -> D128 */
       Iop_InsertExpD128,
 
       /* Support for 128-bit DFP type */