|
From: <sv...@va...> - 2013-01-22 20:25:48
|
carll 2013-01-22 20:25:31 +0000 (Tue, 22 Jan 2013)
New Revision: 2652
Log:
Fix implementation of the DFP integer operands.
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
Modified files:
trunk/priv/guest_ppc_toIR.c
trunk/priv/host_ppc_defs.h
trunk/priv/host_ppc_isel.c
trunk/priv/ir_defs.c
trunk/pub/libvex_ir.h
Modified: trunk/priv/guest_ppc_toIR.c (+128 -89)
===================================================================
--- trunk/priv/guest_ppc_toIR.c 2013-01-22 14:02:05 +00:00 (rev 2651)
+++ trunk/priv/guest_ppc_toIR.c 2013-01-22 20:25:31 +00:00 (rev 2652)
@@ -9526,13 +9526,18 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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,9 +10838,8 @@
assign( without_lmd,
unop( Iop_ReinterpD64asI64,
binop( Iop_InsertExpD64,
+ mkU64( DFP_LONG_BIAS ),
unop( Iop_ReinterpI64asD64,
- mkU64( DFP_LONG_BIAS ) ),
- unop( Iop_ReinterpI64asD64,
binop( Iop_32HLto64,
mkexpr( dbcd_u ),
mkexpr( dbcd_l ) ) ) ) ) );
@@ -10886,9 +10926,8 @@
assign( tmp64,
unop( Iop_ReinterpD64asI64,
binop( Iop_InsertExpD64,
+ mkU64( DFP_LONG_BIAS ),
unop( Iop_ReinterpI64asD64,
- mkU64( DFP_LONG_BIAS ) ),
- unop( Iop_ReinterpI64asD64,
binop( Iop_32HLto64,
binop( Iop_Or32,
mkexpr( dbcd_u ),
@@ -11278,7 +11317,7 @@
*/
assign( result128,
binop( Iop_InsertExpD128,
- unop( Iop_ReinterpI64asD64, mkU64( DFP_EXTND_BIAS ) ),
+ mkU64( DFP_EXTND_BIAS ),
mkexpr( dfp_significand ) ) );
assign( tmp_hi,
Modified: trunk/priv/host_ppc_defs.h (+1 -1)
===================================================================
--- trunk/priv/host_ppc_defs.h 2013-01-22 14:02:05 +00:00 (rev 2651)
+++ trunk/priv/host_ppc_defs.h 2013-01-22 20:25:31 +00:00 (rev 2652)
@@ -375,7 +375,7 @@
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,
Modified: trunk/priv/ir_defs.c (+17 -13)
===================================================================
--- trunk/priv/ir_defs.c 2013-01-22 14:02:05 +00:00 (rev 2651)
+++ trunk/priv/ir_defs.c 2013-01-22 20:25:31 +00:00 (rev 2652)
@@ -2857,22 +2857,22 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 );
Modified: trunk/priv/host_ppc_isel.c (+353 -88)
===================================================================
--- trunk/priv/host_ppc_isel.c 2013-01-22 14:02:05 +00:00 (rev 2651)
+++ trunk/priv/host_ppc_isel.c 2013-01-22 20:25:31 +00:00 (rev 2652)
@@ -1637,6 +1637,46 @@
}
}
+ 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 @@
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 @@
*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,7 +3208,50 @@
*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: {
HReg tHi = newVRegI(env);
@@ -3628,32 +3794,15 @@
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 @@
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 @@
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 @@
}
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 @@
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);
+ } 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;
- 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_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));
- return fr_dst;
+
+ 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 @@
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 @@
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 @@
}
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) );
- addInstr(env, PPCInstr_DfpI64StoD128(fpop, r_dstHi, r_dstLo,
- r_src));
+ // 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_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 @@
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 @@
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 @@
}
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 @@
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);
@@ -4302,11 +4527,51 @@
// 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));
*rHi = r_dstHi;
*rLo = r_dstLo;
return;
}
- }
+ }
ppIRExpr( e );
vpanic( "iselDfp128Expr(ppc64)" );
Modified: trunk/pub/libvex_ir.h (+4 -3)
===================================================================
--- trunk/pub/libvex_ir.h 2013-01-22 14:02:05 +00:00 (rev 2651)
+++ trunk/pub/libvex_ir.h 2013-01-22 20:25:31 +00:00 (rev 2652)
@@ -1095,7 +1095,8 @@
/* 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 @@
/* 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 @@
*/
Iop_InsertExpD64,
- /* I64 x I128 -> D128 */
+ /* I64 x D128 -> D128 */
Iop_InsertExpD128,
/* Support for 128-bit DFP type */
|