s390: Support some more BFP <-> DFP conversions (the ones
that were added in VEX r2727).
Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2728 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index c20bf59..d84125d 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -1974,6 +1974,45 @@
*dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
return;
+ case Iop_D32toF128:
+ case Iop_D64toF128: {
+ IRExpr *irrm;
+ IRExpr *left;
+ s390_dfp_round_t rm;
+ HReg h1; /* virtual reg. to hold source */
+ HReg f0, f2, f4, r1; /* real registers used by PFPO */
+ s390_fp_conv_t fpconv;
+
+ switch (expr->Iex.Binop.op) {
+ case Iop_D32toF128:
+ fpconv = S390_FP_D32_TO_F128;
+ break;
+ case Iop_D64toF128:
+ fpconv = S390_FP_D64_TO_F128;
+ break;
+ default: goto irreducible;
+ }
+
+ f4 = make_fpr(4); /* source */
+ f0 = make_fpr(0); /* destination */
+ f2 = make_fpr(2); /* destination */
+ r1 = make_gpr(1); /* GPR #1 clobbered */
+ irrm = expr->Iex.Binop.arg1;
+ left = expr->Iex.Binop.arg2;
+ rm = get_dfp_rounding_mode(env, irrm);
+ h1 = s390_isel_dfp_expr(env, left);
+ addInstr(env, s390_insn_move(8, f4, h1));
+ addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
+ f4, INVALID_HREG, r1, rm));
+ /* (f0, f2) --> destination */
+ *dst_hi = newVRegF(env);
+ *dst_lo = newVRegF(env);
+ addInstr(env, s390_insn_move(8, *dst_hi, f0));
+ addInstr(env, s390_insn_move(8, *dst_lo, f2));
+
+ return;
+ }
+
case Iop_D128toF128: {
IRExpr *irrm;
IRExpr *left;
@@ -2246,7 +2285,11 @@
case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
+ case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp;
+ case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp;
+ case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp;
case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
+ case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
convert_float:
@@ -2638,12 +2681,24 @@
return;
}
+ case Iop_F32toD128:
case Iop_F64toD128: {
IRExpr *irrm;
IRExpr *left;
s390_dfp_round_t rm;
HReg h1; /* virtual reg. to hold source */
HReg f0, f2, f4, r1; /* real registers used by PFPO */
+ s390_fp_conv_t fpconv;
+
+ switch (expr->Iex.Binop.op) {
+ case Iop_F32toD128: /* (D128, I64) -> D128 */
+ fpconv = S390_FP_F32_TO_D128;
+ break;
+ case Iop_F64toD128: /* (D128, I64) -> D128 */
+ fpconv = S390_FP_F64_TO_D128;
+ break;
+ default: goto irreducible;
+ }
f4 = make_fpr(4); /* source */
f0 = make_fpr(0); /* destination */
@@ -2654,7 +2709,7 @@
rm = get_dfp_rounding_mode(env, irrm);
h1 = s390_isel_float_expr(env, left);
addInstr(env, s390_insn_move(8, f4, h1));
- addInstr(env, s390_insn_fp128_convert(16, S390_FP_F64_TO_D128, f0, f2,
+ addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
f4, INVALID_HREG, r1, rm));
/* (f0, f2) --> destination */
*dst_hi = newVRegF(env);
@@ -2823,7 +2878,12 @@
case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
+ case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
+ case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
+ case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
+ case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
+ case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
convert_dfp:
h1 = s390_isel_dfp_expr(env, left);
@@ -2867,6 +2927,28 @@
return dst;
}
+ convert_bfp128: {
+ s390_dfp_round_t rm;
+ HReg op_hi, op_lo;
+ HReg f0, f4, f6, r1; /* real registers used by PFPO */
+
+ f4 = make_fpr(4); /* source */
+ f6 = make_fpr(6); /* source */
+ f0 = make_fpr(0); /* destination */
+ r1 = make_gpr(1); /* GPR #1 clobbered */
+ s390_isel_float128_expr(&op_hi, &op_lo, env, left);
+ dst = newVRegF(env);
+ rm = get_dfp_rounding_mode(env, irrm);
+ /* operand --> (f4, f6) */
+ addInstr(env, s390_insn_move(8, f4, op_hi));
+ addInstr(env, s390_insn_move(8, f6, op_lo));
+ addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
+ f4, f6, r1, rm));
+ /* f0 --> destination */
+ addInstr(env, s390_insn_move(8, dst, f0));
+ return dst;
+ }
+
case Iop_D128toD64: {
HReg op_hi, op_lo, f13, f15;
s390_dfp_round_t rounding_mode;