From 928e37334ebf07961d1ac52977ac6bb6a595a11b Mon Sep 17 00:00:00 2001 From: Florian Krohm Date: Tue, 1 Jan 2013 22:19:24 +0000 Subject: [PATCH] s390: Add support for DFP "shift significant" insns. Based on patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com). Part of fixing BZ 307113. git-svn-id: svn://svn.valgrind.org/vex/trunk@2626 --- VEX/priv/guest_s390_toIR.c | 76 +++++++++++++++- VEX/priv/host_s390_defs.c | 179 +++++++++++++++++++++++++++++++++++++ VEX/priv/host_s390_defs.h | 20 +++++ VEX/priv/host_s390_isel.c | 64 ++++++++++++- 4 files changed, 333 insertions(+), 6 deletions(-) diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 5e086587a2..750250b935 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -9573,6 +9573,62 @@ s390_irgen_SXTRA(UChar r3, UChar m4, UChar r1, UChar r2) return (m4 == 0) ? "sxtr" : "sxtra"; } +static const HChar * +s390_irgen_SLDT(UChar r3, IRTemp op2addr, UChar r1) +{ + IRTemp op = newTemp(Ity_D64); + + vassert(s390_host_has_dfp); + + assign(op, get_dpr_dw0(r3)); + put_dpr_dw0(r1, binop(Iop_ShlD64, mkexpr(op), unop(Iop_64to8, + binop(Iop_And64, mkexpr(op2addr), mkU64(63))))); + + return "sldt"; +} + +static const HChar * +s390_irgen_SLXT(UChar r3, IRTemp op2addr, UChar r1) +{ + IRTemp op = newTemp(Ity_D128); + + vassert(s390_host_has_dfp); + + assign(op, get_dpr_pair(r3)); + put_dpr_pair(r1, binop(Iop_ShlD128, mkexpr(op), unop(Iop_64to8, + binop(Iop_And64, mkexpr(op2addr), mkU64(63))))); + + return "slxt"; +} + +static const HChar * +s390_irgen_SRDT(UChar r3, IRTemp op2addr, UChar r1) +{ + IRTemp op = newTemp(Ity_D64); + + vassert(s390_host_has_dfp); + + assign(op, get_dpr_dw0(r3)); + put_dpr_dw0(r1, binop(Iop_ShrD64, mkexpr(op), unop(Iop_64to8, + binop(Iop_And64, mkexpr(op2addr), mkU64(63))))); + + return "srdt"; +} + +static const HChar * +s390_irgen_SRXT(UChar r3, IRTemp op2addr, UChar r1) +{ + IRTemp op = newTemp(Ity_D128); + + vassert(s390_host_has_dfp); + + assign(op, get_dpr_pair(r3)); + put_dpr_pair(r1, binop(Iop_ShrD128, mkexpr(op), unop(Iop_64to8, + binop(Iop_And64, mkexpr(op2addr), mkU64(63))))); + + return "srxt"; +} + static const HChar * s390_irgen_TDCET(UChar r1, IRTemp op2addr) { @@ -15103,10 +15159,22 @@ s390_decode_6byte_and_irgen(UChar *bytes) case 0xed000000003dULL: /* MYH */ goto unimplemented; case 0xed000000003eULL: /* MAD */ goto unimplemented; case 0xed000000003fULL: /* MSD */ goto unimplemented; - case 0xed0000000040ULL: /* SLDT */ goto unimplemented; - case 0xed0000000041ULL: /* SRDT */ goto unimplemented; - case 0xed0000000048ULL: /* SLXT */ goto unimplemented; - case 0xed0000000049ULL: /* SRXT */ goto unimplemented; + case 0xed0000000040ULL: s390_format_RXF_FRRDF(s390_irgen_SLDT, + ovl.fmt.RXF.r3, ovl.fmt.RXF.x2, + ovl.fmt.RXF.b2, ovl.fmt.RXF.d2, + ovl.fmt.RXF.r1); goto ok; + case 0xed0000000041ULL: s390_format_RXF_FRRDF(s390_irgen_SRDT, + ovl.fmt.RXF.r3, ovl.fmt.RXF.x2, + ovl.fmt.RXF.b2, ovl.fmt.RXF.d2, + ovl.fmt.RXF.r1); goto ok; + case 0xed0000000048ULL: s390_format_RXF_FRRDF(s390_irgen_SLXT, + ovl.fmt.RXF.r3, ovl.fmt.RXF.x2, + ovl.fmt.RXF.b2, ovl.fmt.RXF.d2, + ovl.fmt.RXF.r1); goto ok; + case 0xed0000000049ULL: s390_format_RXF_FRRDF(s390_irgen_SRXT, + ovl.fmt.RXF.r3, ovl.fmt.RXF.x2, + ovl.fmt.RXF.b2, ovl.fmt.RXF.d2, + ovl.fmt.RXF.r1); goto ok; case 0xed0000000050ULL: s390_format_RXE_FRRD(s390_irgen_TDCET, ovl.fmt.RXE.r1, ovl.fmt.RXE.x2, ovl.fmt.RXE.b2, ovl.fmt.RXE.d2); goto ok; diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 4645376836..6ba22d0ce2 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -731,6 +731,16 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) } break; + case S390_INSN_DFP_INTOP: + addHRegUse(u, HRmWrite, insn->variant.dfp_intop.dst_hi); + addHRegUse(u, HRmRead, insn->variant.dfp_intop.op2); + addHRegUse(u, HRmRead, insn->variant.dfp_intop.op3_hi); + if (insn->size == 16) { + addHRegUse(u, HRmWrite, insn->variant.dfp_intop.dst_lo); + addHRegUse(u, HRmRead, insn->variant.dfp_intop.op3_lo); + } + break; + case S390_INSN_DFP_COMPARE: addHRegUse(u, HRmWrite, insn->variant.dfp_compare.dst); addHRegUse(u, HRmRead, insn->variant.dfp_compare.op1_hi); /* left */ @@ -1020,6 +1030,21 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) } break; + case S390_INSN_DFP_INTOP: + insn->variant.dfp_intop.dst_hi = + lookupHRegRemap(m, insn->variant.dfp_intop.dst_hi); + insn->variant.dfp_intop.op2 = + lookupHRegRemap(m, insn->variant.dfp_intop.op2); + insn->variant.dfp_intop.op3_hi = + lookupHRegRemap(m, insn->variant.dfp_intop.op3_hi); + if (insn->size == 16) { + insn->variant.dfp_intop.dst_lo = + lookupHRegRemap(m, insn->variant.dfp_intop.dst_lo); + insn->variant.dfp_intop.op3_lo = + lookupHRegRemap(m, insn->variant.dfp_intop.op3_lo); + } + break; + case S390_INSN_DFP_COMPARE: insn->variant.dfp_compare.dst = lookupHRegRemap(m, insn->variant.dfp_compare.dst); @@ -1304,6 +1329,21 @@ emit_RX(UChar *p, UInt op, UChar r1, UChar x2, UChar b2, UShort d2) } +static UChar * +emit_RXF(UChar *p, ULong op, UChar r3, UChar x2, UChar b2, UShort d2, UChar r1) +{ + ULong the_insn = op; + + the_insn |= ((ULong)r3) << 36; + the_insn |= ((ULong)x2) << 32; + the_insn |= ((ULong)b2) << 28; + the_insn |= ((ULong)d2) << 16; + the_insn |= ((ULong)r1) << 12; + + return emit_6bytes(p, the_insn); +} + + static UChar * emit_RXY(UChar *p, ULong op, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2) { @@ -4286,6 +4326,54 @@ s390_emit_SXTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2) } +static UChar * +s390_emit_SLDT(UChar *p, UChar r3, UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "sldt", r1, r3, 0, 0, r2); + } + + return emit_RXF(p, 0xED0000000040, r3, 0, r2, 0, r1); +} + + +static UChar * +s390_emit_SLXT(UChar *p, UChar r3, UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "slxt", r1, r3, 0, 0, r2); + } + + return emit_RXF(p, 0xED0000000048, r3, 0, r2, 0, r1); +} + + +static UChar * +s390_emit_SRDT(UChar *p, UChar r3, UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "srdt", r1, r3, 0, 0, r2); + } + + return emit_RXF(p, 0xED0000000041, r3, 0, r2, 0, r1); +} + + +static UChar * +s390_emit_SRXT(UChar *p, UChar r3, UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "srxt", r1, r3, 0, 0, r2); + } + + return emit_RXF(p, 0xED0000000049, r3, 0, r2, 0, r1); +} + + static UChar * s390_emit_LOCGR(UChar *p, UChar m3, UChar r1, UChar r2) { @@ -5438,6 +5526,27 @@ s390_insn_dfp_unop(UChar size, s390_dfp_unop_t tag, HReg dst, HReg op) } +s390_insn * +s390_insn_dfp_intop(UChar size, s390_dfp_intop_t tag, HReg dst, HReg op2, + HReg op3) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + vassert(size == 8); + + insn->tag = S390_INSN_DFP_INTOP; + insn->size = size; + insn->variant.dfp_intop.tag = tag; + insn->variant.dfp_intop.dst_hi = dst; + insn->variant.dfp_intop.op2 = op2; + insn->variant.dfp_intop.op3_hi = op3; + insn->variant.dfp_intop.dst_lo = INVALID_HREG; + insn->variant.dfp_intop.op3_lo = INVALID_HREG; + + return insn; +} + + s390_insn * s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t tag, HReg dst, HReg op1, HReg op2) @@ -5532,6 +5641,29 @@ s390_insn_dfp128_unop(UChar size, s390_dfp_unop_t tag, HReg dst, } +s390_insn * +s390_insn_dfp128_intop(UChar size, s390_dfp_intop_t tag, HReg dst_hi, + HReg dst_lo, HReg op2, HReg op3_hi, HReg op3_lo) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + vassert(size == 16); + vassert(is_valid_fp128_regpair(dst_hi, dst_lo)); + vassert(is_valid_fp128_regpair(op3_hi, op3_lo)); + + insn->tag = S390_INSN_DFP_INTOP; + insn->size = size; + insn->variant.dfp_intop.tag = tag; + insn->variant.dfp_intop.dst_hi = dst_hi; + insn->variant.dfp_intop.dst_lo = dst_lo; + insn->variant.dfp_intop.op2 = op2; + insn->variant.dfp_intop.op3_hi = op3_hi; + insn->variant.dfp_intop.op3_lo = op3_lo; + + return insn; +} + + s390_insn * 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) @@ -6207,6 +6339,17 @@ s390_insn_as_string(const s390_insn *insn) insn->variant.dfp_unop.op_hi); break; + case S390_INSN_DFP_INTOP: + switch (insn->variant.dfp_intop.tag) { + case S390_DFP_SHIFT_LEFT: op = "v-dshl"; break; + case S390_DFP_SHIFT_RIGHT: op = "v-dshr"; break; + default: goto fail; + } + s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.dfp_intop.dst_hi, + insn->variant.dfp_intop.op2, + insn->variant.dfp_intop.op3_hi); + break; + case S390_INSN_DFP_COMPARE: switch (insn->variant.dfp_compare.tag) { case S390_DFP_COMPARE: op = "v-dcmp"; break; @@ -8412,6 +8555,38 @@ s390_insn_dfp_unop_emit(UChar *buf, const s390_insn *insn) } +static UChar * +s390_insn_dfp_intop_emit(UChar *buf, const s390_insn *insn) +{ + UInt r1 = hregNumber(insn->variant.dfp_intop.dst_hi); + UInt r2 = hregNumber(insn->variant.dfp_intop.op2); + UInt r3 = hregNumber(insn->variant.dfp_intop.op3_hi); + + switch (insn->size) { + case 8: + switch (insn->variant.dfp_intop.tag) { + case S390_DFP_SHIFT_LEFT: return s390_emit_SLDT(buf, r3, r1, r2); + case S390_DFP_SHIFT_RIGHT: return s390_emit_SRDT(buf, r3, r1, r2); + default: goto fail; + } + break; + + case 16: + switch (insn->variant.dfp_intop.tag) { + case S390_DFP_SHIFT_LEFT: return s390_emit_SLXT(buf, r3, r1, r2); + case S390_DFP_SHIFT_RIGHT: return s390_emit_SRXT(buf, r3, r1, r2); + default: goto fail; + } + break; + + default: goto fail; + } + + fail: + vpanic("s390_insn_dfp_intop_emit"); +} + + static UChar * s390_insn_dfp_compare_emit(UChar *buf, const s390_insn *insn) { @@ -9112,6 +9287,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn, end = s390_insn_dfp_unop_emit(buf, insn); break; + case S390_INSN_DFP_INTOP: + end = s390_insn_dfp_intop_emit(buf, insn); + break; + case S390_INSN_DFP_COMPARE: end = s390_insn_dfp_compare_emit(buf, insn); break; diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index 4e7fcca2e8..ba64bd15d3 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -142,6 +142,7 @@ typedef enum { S390_INSN_BFP_CONVERT, S390_INSN_DFP_BINOP, /* Decimal floating point */ S390_INSN_DFP_UNOP, + S390_INSN_DFP_INTOP, S390_INSN_DFP_COMPARE, S390_INSN_DFP_CONVERT, S390_INSN_MFENCE, @@ -261,6 +262,12 @@ typedef enum { S390_DFP_EXTRACT_SIG_D128, } s390_dfp_unop_t; +/* The DFP operations with 2 operands one of them being integer */ +typedef enum { + S390_DFP_SHIFT_LEFT, + S390_DFP_SHIFT_RIGHT +} s390_dfp_intop_t; + /* The kind of DFP compare operations */ typedef enum { S390_DFP_COMPARE, @@ -457,6 +464,14 @@ typedef struct { HReg op_hi; /* 128-bit operand high part; 64-bit opnd */ HReg op_lo; /* 128-bit operand low part */ } dfp_unop; + struct { + s390_dfp_intop_t tag; + HReg dst_hi; /* 128-bit result high part; 64-bit result */ + HReg dst_lo; /* 128-bit result low part */ + HReg op2; /* integer operand */ + HReg op3_hi; /* 128-bit operand high part; 64-bit opnd */ + HReg op3_lo; /* 128-bit operand low part */ + } dfp_intop; struct { s390_dfp_conv_t tag; s390_dfp_round_t rounding_mode; @@ -583,6 +598,8 @@ 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_unop(UChar size, s390_dfp_unop_t, HReg dst, HReg op); +s390_insn *s390_insn_dfp_intop(UChar size, s390_dfp_intop_t, HReg dst, + HReg op2, HReg op3); 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, @@ -593,6 +610,9 @@ s390_insn *s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t, HReg dst_hi, s390_dfp_round_t rounding_mode); s390_insn *s390_insn_dfp128_unop(UChar size, s390_dfp_unop_t, HReg dst, HReg op_hi, HReg op_lo); +s390_insn *s390_insn_dfp128_intop(UChar size, s390_dfp_intop_t, HReg dst_hi, + HReg dst_lo, HReg op2, + HReg op3_hi, HReg op3_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); diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index bb5aef29b2..e5851195b6 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -2443,12 +2443,50 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, /* --------- BINARY OP --------- */ case Iex_Binop: { + switch (expr->Iex.Binop.op) { case Iop_D64HLtoD128: *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1); *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2); return; + case Iop_ShlD128: + case Iop_ShrD128: { + HReg op1_hi, op1_lo, op2, f9, f11, f13, f15; + s390_dfp_intop_t intop; + IRExpr *left = expr->Iex.Binop.arg1; + IRExpr *right = expr->Iex.Binop.arg2; + + switch (expr->Iex.Binop.op) { + case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT; break; + case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break; + default: goto irreducible; + } + + /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */ + f9 = make_fpr(9); /* 128 bit dfp operand */ + f11 = make_fpr(11); + + f13 = make_fpr(13); /* 128 bit dfp destination */ + f15 = make_fpr(15); + + s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* dfp operand */ + addInstr(env, s390_insn_move(8, f9, op1_hi)); + addInstr(env, s390_insn_move(8, f11, op1_lo)); + + op2 = s390_isel_int_expr(env, right); /* int operand */ + + addInstr(env, + s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11)); + + /* Move result to virtual destination register */ + *dst_hi = newVRegF(env); + *dst_lo = newVRegF(env); + addInstr(env, s390_insn_move(8, *dst_hi, f13)); + addInstr(env, s390_insn_move(8, *dst_lo, f15)); + return; + } + default: goto irreducible; } @@ -2587,8 +2625,6 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) rounding_mode)); return dst; } - default: - goto irreducible; case Iop_D128toD64: { HReg op_hi, op_lo, f13, f15; @@ -2620,6 +2656,30 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) return dst; } + case Iop_ShlD64: + case Iop_ShrD64: { + HReg op2; + HReg op3; + s390_dfp_intop_t intop; + IRExpr *op1 = expr->Iex.Binop.arg1; + IRExpr *shift = expr->Iex.Binop.arg2; + + switch (expr->Iex.Binop.op) { + case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT; break; + case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break; + default: goto irreducible; + } + + op2 = s390_isel_int_expr(env, shift); + op3 = s390_isel_dfp_expr(env, op1); + dst = newVRegF(env); + + addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3)); + return dst; + } + + default: + goto irreducible; } } -- 2.47.2