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",
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;
}
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",
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.
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) {
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,
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
/* 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,
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");
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
/* 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 ),
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");
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 ) );
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");
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 ) );
* 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:
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
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");
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 );
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 ),
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,
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 ),
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,
*/
assign( result128,
binop( Iop_InsertExpD128,
- unop( Iop_ReinterpI64asD64, mkU64( DFP_EXTND_BIAS ) ),
+ mkU64( DFP_EXTND_BIAS ),
mkexpr( dfp_significand ) ) );
assign( tmp_hi,
}
}
+ 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;
}
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;
}
*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;
}
*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: {
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 );
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) {
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));
}
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);
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) {
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;
}
}
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;
}
}
}
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;
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));
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;
}
if (fpop != Pfp_INVALID) {
- HReg r_dstHi = newVRegV( env );
- HReg r_dstLo = newVRegV( env );
HReg r_srcRHi = newVRegV( env );
HReg r_srcRLo = newVRegV( env );
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);
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));
*rLo = r_dstLo;
return;
}
- }
+ }
ppIRExpr( e );
vpanic( "iselDfp128Expr(ppc64)" );