From: Carl Love Date: Tue, 22 Jan 2013 20:25:31 +0000 (+0000) Subject: Fix implementation of the DFP integer operands. X-Git-Tag: svn/VALGRIND_3_9_0^2~142 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d6f912b582a53861baba327b5e3dd403008bca1;p=thirdparty%2Fvalgrind.git 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 git-svn-id: svn://svn.valgrind.org/vex/trunk@2652 --- diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c index cab2a43788..b31d2baf7d 100644 --- a/VEX/priv/guest_ppc_toIR.c +++ b/VEX/priv/guest_ppc_toIR.c @@ -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, diff --git a/VEX/priv/host_ppc_defs.h b/VEX/priv/host_ppc_defs.h index b1a567c03e..9c2d05de1e 100644 --- a/VEX/priv/host_ppc_defs.h +++ b/VEX/priv/host_ppc_defs.h @@ -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, diff --git a/VEX/priv/host_ppc_isel.c b/VEX/priv/host_ppc_isel.c index 50dd9b8639..e379d86250 100644 --- a/VEX/priv/host_ppc_isel.c +++ b/VEX/priv/host_ppc_isel.c @@ -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)" ); diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index d81a37b7e4..3ae2bdac14 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -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 ); diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index c132995320..8b992d365d 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -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 */