s390x: Support "compare biased exponent" insns CEDTR, CEXTR.
To do that properly, two new IROps are needed: Iop_CmpExpD64 and
Iop_CmpExpD128. It might seem that extracting the exponents using
Iop_ExtractExpD64/D128 and comparing the values could be used here.
But that only works for finite DFP values. Hence, the new IROps.
Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
This is part of fixing BZ 307113.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2617 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index ec47531..f90f05d 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -9283,6 +9283,44 @@
}
static const HChar *
+s390_irgen_CEDTR(UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp cc_vex = newTemp(Ity_I32);
+ IRTemp cc_s390 = newTemp(Ity_I32);
+
+ vassert(s390_host_has_dfp);
+ assign(op1, get_dpr_dw0(r1));
+ assign(op2, get_dpr_dw0(r2));
+ assign(cc_vex, binop(Iop_CmpExpD64, mkexpr(op1), mkexpr(op2)));
+
+ assign(cc_s390, convert_vex_dfpcc_to_s390(cc_vex));
+ s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
+
+ return "cedtr";
+}
+
+static const HChar *
+s390_irgen_CEXTR(UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D128);
+ IRTemp op2 = newTemp(Ity_D128);
+ IRTemp cc_vex = newTemp(Ity_I32);
+ IRTemp cc_s390 = newTemp(Ity_I32);
+
+ vassert(s390_host_has_dfp);
+ assign(op1, get_dpr_pair(r1));
+ assign(op2, get_dpr_pair(r2));
+ assign(cc_vex, binop(Iop_CmpExpD128, mkexpr(op1), mkexpr(op2)));
+
+ assign(cc_s390, convert_vex_dfpcc_to_s390(cc_vex));
+ s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
+
+ return "cextr";
+}
+
+static const HChar *
s390_irgen_DDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
{
IRTemp op1 = newTemp(Ity_D64);
@@ -13534,14 +13572,16 @@
case 0xb3f1: /* CDGTR */ goto unimplemented;
case 0xb3f2: /* CDUTR */ goto unimplemented;
case 0xb3f3: /* CDSTR */ goto unimplemented;
- case 0xb3f4: /* CEDTR */ goto unimplemented;
+ case 0xb3f4: s390_format_RRE_FF(s390_irgen_CEDTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3f5: /* QADTR */ goto unimplemented;
case 0xb3f6: /* IEDTR */ goto unimplemented;
case 0xb3f7: /* RRDTR */ goto unimplemented;
case 0xb3f9: /* CXGTR */ goto unimplemented;
case 0xb3fa: /* CXUTR */ goto unimplemented;
case 0xb3fb: /* CXSTR */ goto unimplemented;
- case 0xb3fc: /* CEXTR */ goto unimplemented;
+ case 0xb3fc: s390_format_RRE_FF(s390_irgen_CEXTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3fd: /* QAXTR */ goto unimplemented;
case 0xb3fe: /* IEXTR */ goto unimplemented;
case 0xb3ff: /* RRXTR */ goto unimplemented;
diff --git a/priv/host_s390_defs.c b/priv/host_s390_defs.c
index 48695ba..3a82222 100644
--- a/priv/host_s390_defs.c
+++ b/priv/host_s390_defs.c
@@ -4009,6 +4009,26 @@
static UChar *
+s390_emit_CEDTR(UChar *p, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC3(MNM, FPR, FPR), "cedtr", r1, r2);
+
+ return emit_RRE(p, 0xb3f40000, r1, r2);
+}
+
+
+static UChar *
+s390_emit_CEXTR(UChar *p, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC3(MNM, FPR, FPR), "cextr", r1, r2);
+
+ return emit_RRE(p, 0xb3fc0000, r1, r2);
+}
+
+
+static UChar *
s390_emit_DDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
{
vassert(s390_host_has_dfp);
@@ -5292,7 +5312,8 @@
s390_insn *
-s390_insn_dfp_compare(UChar size, HReg dst, HReg op1, HReg op2)
+s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t tag, HReg dst,
+ HReg op1, HReg op2)
{
s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
@@ -5300,6 +5321,7 @@
insn->tag = S390_INSN_DFP_COMPARE;
insn->size = size;
+ insn->variant.dfp_compare.tag = tag;
insn->variant.dfp_compare.dst = dst;
insn->variant.dfp_compare.op1_hi = op1;
insn->variant.dfp_compare.op2_hi = op2;
@@ -5362,8 +5384,8 @@
s390_insn *
-s390_insn_dfp128_compare(UChar size, HReg dst, HReg op1_hi, HReg op1_lo,
- HReg op2_hi, HReg op2_lo)
+s390_insn_dfp128_compare(UChar size, s390_dfp_cmp_t tag, HReg dst, HReg op1_hi,
+ HReg op1_lo, HReg op2_hi, HReg op2_lo)
{
s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
@@ -5373,6 +5395,7 @@
insn->tag = S390_INSN_DFP_COMPARE;
insn->size = size;
+ insn->variant.dfp_compare.tag = tag;
insn->variant.dfp_compare.dst = dst;
insn->variant.dfp_compare.op1_hi = op1_hi;
insn->variant.dfp_compare.op1_lo = op1_lo;
@@ -6025,7 +6048,12 @@
}
case S390_INSN_DFP_COMPARE:
- s390_sprintf(buf, "%M %R,%R,%R", "v-dcmp", insn->variant.dfp_compare.dst,
+ switch (insn->variant.dfp_compare.tag) {
+ case S390_DFP_COMPARE: op = "v-dcmp"; break;
+ case S390_DFP_COMPARE_EXP: op = "v-dcmpexp"; break;
+ default: goto fail;
+ }
+ s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.dfp_compare.dst,
insn->variant.dfp_compare.op1_hi,
insn->variant.dfp_compare.op2_hi);
break;
@@ -8215,8 +8243,22 @@
UInt r2 = hregNumber(insn->variant.dfp_compare.op2_hi);
switch (insn->size) {
- case 8: buf = s390_emit_CDTR(buf, r1, r2); break;
- case 16: buf = s390_emit_CXTR(buf, r1, r2); break;
+ case 8:
+ switch(insn->variant.dfp_compare.tag) {
+ case S390_DFP_COMPARE: buf = s390_emit_CDTR(buf, r1, r2); break;
+ case S390_DFP_COMPARE_EXP: buf = s390_emit_CEDTR(buf, r1, r2); break;
+ default: goto fail;
+ }
+ break;
+
+ case 16:
+ switch(insn->variant.dfp_compare.tag) {
+ case S390_DFP_COMPARE: buf = s390_emit_CXTR(buf, r1, r2); break;
+ case S390_DFP_COMPARE_EXP: buf = s390_emit_CEXTR(buf, r1, r2); break;
+ default: goto fail;
+ }
+ break;
+
default: goto fail;
}
diff --git a/priv/host_s390_defs.h b/priv/host_s390_defs.h
index 03b6b8d..4b795c4 100644
--- a/priv/host_s390_defs.h
+++ b/priv/host_s390_defs.h
@@ -254,6 +254,12 @@
S390_DFP_DIV
} s390_dfp_binop_t;
+/* The kind of DFP compare operations */
+typedef enum {
+ S390_DFP_COMPARE,
+ S390_DFP_COMPARE_EXP,
+} s390_dfp_cmp_t;
+
/* The details of a CDAS insn. Carved out to keep the size of
s390_insn low */
@@ -446,6 +452,7 @@
HReg op_lo; /* 128-bit operand low part */
} dfp_convert;
struct {
+ s390_dfp_cmp_t tag;
HReg dst; /* condition code in s390 encoding */
HReg op1_hi; /* 128-bit operand high part; 64-bit opnd 1 */
HReg op1_lo; /* 128-bit operand low part */
@@ -560,15 +567,17 @@
s390_insn *s390_insn_dfp_binop(UChar size, s390_dfp_binop_t, HReg dst,
HReg op2, HReg op3,
s390_dfp_round_t rounding_mode);
-s390_insn *s390_insn_dfp_compare(UChar size, HReg dst, HReg op1, HReg op2);
+s390_insn *s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t, HReg dst,
+ HReg op1, HReg op2);
s390_insn *s390_insn_dfp_convert(UChar size, s390_dfp_conv_t tag, HReg dst,
HReg op, s390_dfp_round_t);
s390_insn *s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t, HReg dst_hi,
HReg dst_lo, HReg op2_hi, HReg op2_lo,
HReg op3_hi, HReg op3_lo,
s390_dfp_round_t rounding_mode);
-s390_insn *s390_insn_dfp128_compare(UChar size, HReg dst, HReg op1_hi,
- HReg op1_lo, HReg op2_hi, HReg op2_lo);
+s390_insn *s390_insn_dfp128_compare(UChar size, s390_dfp_cmp_t, HReg dst,
+ HReg op1_hi, HReg op1_lo, HReg op2_hi,
+ HReg op2_lo);
s390_insn *s390_insn_dfp128_convert_to(UChar size, s390_dfp_conv_t,
HReg dst_hi, HReg dst_lo, HReg op);
s390_insn *s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t,
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index 568e4c3..3027045 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -1218,21 +1218,29 @@
return convert_s390_to_vex_bfpcc(env, cc_s390);
}
- case Iop_CmpD64: {
+ case Iop_CmpD64:
+ case Iop_CmpExpD64: {
HReg cc_s390, h2;
+ s390_dfp_cmp_t cmp;
h1 = s390_isel_dfp_expr(env, arg1);
h2 = s390_isel_dfp_expr(env, arg2);
cc_s390 = newVRegI(env);
- size = 8;
- addInstr(env, s390_insn_dfp_compare(size, cc_s390, h1, h2));
+ switch(expr->Iex.Binop.op) {
+ case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
+ case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
+ default: goto irreducible;
+ }
+ addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
return convert_s390_to_vex_dfpcc(env, cc_s390);
}
- case Iop_CmpD128: {
+ case Iop_CmpD128:
+ case Iop_CmpExpD128: {
HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
+ s390_dfp_cmp_t cmp;
s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
@@ -1252,8 +1260,13 @@
addInstr(env, s390_insn_move(8, f13, op2_hi));
addInstr(env, s390_insn_move(8, f15, op2_lo));
- res = newVRegI(env);
- addInstr(env, s390_insn_dfp128_compare(16, cc_s390, f12, f14, f13, f15));
+ switch(expr->Iex.Binop.op) {
+ case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
+ case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
+ default: goto irreducible;
+ }
+ addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
+ f13, f15));
return convert_s390_to_vex_dfpcc(env, cc_s390);
}
diff --git a/priv/ir_defs.c b/priv/ir_defs.c
index 39c5f26..35a9ee9 100644
--- a/priv/ir_defs.c
+++ b/priv/ir_defs.c
@@ -985,11 +985,13 @@
case Iop_ExtractExpD128: vex_printf("Iop_ExtractExpD128"); return;
case Iop_InsertExpD64: vex_printf("Iop_InsertExpD64"); return;
case Iop_InsertExpD128: vex_printf("Iop_InsertExpD128"); return;
- case Iop_CmpD64: vex_printf("CmpD64"); return;
- case Iop_CmpD128: vex_printf("CmpD128"); return;
- case Iop_D64HLtoD128: vex_printf("D64HLtoD128"); return;
- case Iop_D128HItoD64: vex_printf("D128HItoD64"); return;
- case Iop_D128LOtoD64: vex_printf("D128LOtoD64"); return;
+ case Iop_CmpD64: vex_printf("CmpD64"); return;
+ case Iop_CmpD128: vex_printf("CmpD128"); return;
+ case Iop_CmpExpD64: vex_printf("CmpExpD64"); return;
+ case Iop_CmpExpD128: vex_printf("CmpExpD128"); return;
+ case Iop_D64HLtoD128: vex_printf("D64HLtoD128"); return;
+ case Iop_D128HItoD64: vex_printf("D128HItoD64"); return;
+ case Iop_D128LOtoD64: vex_printf("D128LOtoD64"); return;
case Iop_SignificanceRoundD64: vex_printf("Iop_SignificanceRoundD64");
return;
case Iop_SignificanceRoundD128: vex_printf("Iop_SignificanceRoundD128");
@@ -2800,9 +2802,11 @@
BINARY(ity_RMode, Ity_D64, Ity_D64);
case Iop_CmpD64:
+ case Iop_CmpExpD64:
BINARY(Ity_D64,Ity_D64, Ity_I32);
case Iop_CmpD128:
+ case Iop_CmpExpD128:
BINARY(Ity_D128,Ity_D128, Ity_I32);
case Iop_QuantizeD64: