From: Florian Krohm Date: Wed, 26 Dec 2012 17:47:19 +0000 (+0000) Subject: s390x: Support "compare biased exponent" insns CEDTR, CEXTR. X-Git-Tag: svn/VALGRIND_3_9_0^2~169 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbdced75cba264e05c06c0da3b5bd878dc312728;p=thirdparty%2Fvalgrind.git 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 --- diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index ec475318db..f90f05da7f 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -9282,6 +9282,44 @@ s390_irgen_CXTR(UChar r1, UChar r2) return "cxtr"; } +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) { @@ -13534,14 +13572,16 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 48695ba1fe..3a822222ba 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -4008,6 +4008,26 @@ s390_emit_CXTR(UChar *p, UChar r1, UChar r2) } +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) { @@ -5292,7 +5312,8 @@ s390_insn_dfp_binop(UChar size, s390_dfp_binop_t tag, HReg dst, HReg op2, 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 @@ s390_insn_dfp_compare(UChar size, HReg dst, HReg op1, HReg op2) 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_dfp128_binop(UChar size, s390_dfp_binop_t tag, HReg dst_hi, 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 @@ s390_insn_dfp128_compare(UChar size, HReg dst, HReg op1_hi, HReg op1_lo, 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 @@ s390_insn_as_string(const s390_insn *insn) } 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 @@ s390_insn_dfp_compare_emit(UChar *buf, const s390_insn *insn) 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/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index 03b6b8d80a..4b795c4a80 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -254,6 +254,12 @@ typedef enum { 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 @@ typedef struct { 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_bfp128_convert_from(UChar size, s390_bfp_conv_t, 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/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 568e4c3b25..3027045049 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -1218,21 +1218,29 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) 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 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) 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/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index 39c5f26d39..35a9ee9a00 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -985,11 +985,13 @@ void ppIROp ( IROp op ) 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 @@ void typeOfPrimop ( IROp op, 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: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index ad2181602c..8280e53c71 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -1073,6 +1073,13 @@ typedef /* D128 x D128 -> IRCmpD128Result(I32) */ Iop_CmpD128, + /* COMPARE BIASED EXPONENET INSTRUCTIONS + * D64 x D64 -> IRCmpD64Result(I32) */ + Iop_CmpExpD64, + + /* D128 x D128 -> IRCmpD128Result(I32) */ + Iop_CmpExpD128, + /* QUANTIZE AND ROUND INSTRUCTIONS * The source operand is converted and rounded to the form with the * immediate exponent specified by the rounding and exponent parameter.