insns. Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
This is part of fixing BZ 307113.
[ revision 2621 was also implemented by Maran. ]
git-svn-id: svn://svn.valgrind.org/vex/trunk@2622
S390_CC_OP_BFP_64_TO_UINT_64 = 40,
S390_CC_OP_BFP_128_TO_UINT_64 = 41,
S390_CC_OP_DFP_RESULT_64 = 42,
- S390_CC_OP_DFP_RESULT_128 = 43
+ S390_CC_OP_DFP_RESULT_128 = 43,
+ S390_CC_OP_DFP_TDC_32 = 44,
+ S390_CC_OP_DFP_TDC_64 = 45,
+ S390_CC_OP_DFP_TDC_128 = 46,
+ S390_CC_OP_DFP_TDG_32 = 47,
+ S390_CC_OP_DFP_TDG_64 = 48,
+ S390_CC_OP_DFP_TDG_128 = 49
};
/*------------------------------------------------------------*/
| S390_CC_OP_BFP_128_TO_UINT_64 | F source hi 64 bits | F source low 64 bits | Z rounding mode |
| S390_CC_OP_DFP_RESULT_64 | D result | | |
| S390_CC_OP_DFP_RESULT_128 | D result hi 64 bits | D result low 64 bits | |
+ | S390_CC_OP_DFP_TDC_32 | D value | Z class | |
+ | S390_CC_OP_DFP_TDC_64 | D value | Z class | |
+ | S390_CC_OP_DFP_TDC_128 | D value hi 64 bits | D value low 64 bits | Z class |
+ | S390_CC_OP_DFP_TDG_32 | D value | Z group | |
+ | S390_CC_OP_DFP_TDG_64 | D value | Z group | |
+ | S390_CC_OP_DFP_TDG_128 | D value hi 64 bits | D value low 64 bits | Z group |
+--------------------------------+-----------------------+----------------------+-----------------+
*/
psw >> 28; /* cc */ \
})
+#define S390_CC_FOR_DFP_TD(opcode,cc_dep1,cc_dep2) \
+({ \
+ __asm__ volatile ( \
+ opcode ",%[value],0(%[class])\n\t" \
+ "ipm %[psw]\n\t" : [psw] "=d"(psw) \
+ : [value] "f"(cc_dep1), \
+ [class] "a"(cc_dep2) \
+ : "cc"); \
+ psw >> 28; /* cc */ \
+})
+
+#define S390_CC_FOR_DFP128_TD(opcode,cc_dep1,cc_dep2,cc_ndep) \
+({ \
+ /* Recover the original DEP2 value. See comment near \
+ s390_cc_thunk_put1d128Z for rationale. */ \
+ cc_dep2 = cc_dep2 ^ cc_ndep; \
+ __asm__ volatile ( \
+ "ldr 4,%[high]\n\t" \
+ "ldr 6,%[low]\n\t" \
+ opcode ",4,0(%[class])\n\t" \
+ "ipm %[psw]\n\t" : [psw] "=d"(psw) \
+ : [high] "f"(cc_dep1), [low] "f"(cc_dep2), \
+ [class] "a"(cc_ndep) \
+ : "cc", "f4", "f6"); \
+ psw >> 28; /* cc */ \
+})
+
/* Return the value of the condition code from the supplied thunk parameters.
This is not the value of the PSW. It is the value of the 2 CC bits within
case S390_CC_OP_DFP_RESULT_128:
return S390_CC_FOR_DFP128_RESULT(cc_dep1, cc_dep2);
+ case S390_CC_OP_DFP_TDC_32: /* TDCET */
+ return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000050", cc_dep1, cc_dep2);
+
+ case S390_CC_OP_DFP_TDC_64: /* TDCDT */
+ return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000054", cc_dep1, cc_dep2);
+
+ case S390_CC_OP_DFP_TDC_128: /* TDCXT */
+ return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000058", cc_dep1,
+ cc_dep2, cc_ndep);
+
+ case S390_CC_OP_DFP_TDG_32: /* TDGET */
+ return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000051", cc_dep1, cc_dep2);
+
+ case S390_CC_OP_DFP_TDG_64: /* TDGDT */
+ return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000055", cc_dep1, cc_dep2);
+
+ case S390_CC_OP_DFP_TDG_128: /* TDGXT */
+ return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000059", cc_dep1,
+ cc_dep2, cc_ndep);
+
default:
break;
}
}
+/* Write a 128-bit decimal floating point value and an integer into the flags
+ thunk. The integer value is zero-extended first. */
+static void
+s390_cc_thunk_put1d128Z(UInt opc, IRTemp d1, IRTemp nd)
+{
+ IRExpr *op, *hi, *lo, *lox, *ndep;
+
+ op = mkU64(opc);
+ hi = unop(Iop_D128HItoD64, mkexpr(d1));
+ lo = unop(Iop_ReinterpD64asI64, unop(Iop_D128LOtoD64, mkexpr(d1)));
+ ndep = s390_cc_widen(nd, False);
+
+ lox = binop(Iop_Xor64, lo, ndep); /* convey dependency */
+
+ s390_cc_thunk_fill(op, hi, lox, ndep);
+}
+
+
static void
s390_cc_set(UInt val)
{
return (m4 == 0) ? "dxtr" : "dxtra";
}
+static const HChar *
+s390_irgen_ESDTR(UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ put_gpr_dw0(r1, unop(Iop_ExtractSigD64, get_dpr_dw0(r2)));
+ return "esdtr";
+}
+
+static const HChar *
+s390_irgen_ESXTR(UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ put_gpr_dw0(r1, unop(Iop_ExtractSigD128, get_dpr_pair(r2)));
+ return "esxtr";
+}
+
static const HChar *
s390_irgen_LDETR(UChar m4 __attribute__((unused)), UChar r1, UChar r2)
{
return (m4 == 0) ? "sxtr" : "sxtra";
}
+static const HChar *
+s390_irgen_TDCET(UChar r1, IRTemp op2addr)
+{
+ IRTemp value = newTemp(Ity_D32);
+
+ vassert(s390_host_has_dfp);
+ assign(value, get_dpr_w0(r1));
+
+ s390_cc_thunk_putFZ(S390_CC_OP_DFP_TDC_32, value, op2addr);
+
+ return "tdcet";
+}
+
+static const HChar *
+s390_irgen_TDCDT(UChar r1, IRTemp op2addr)
+{
+ IRTemp value = newTemp(Ity_D64);
+
+ vassert(s390_host_has_dfp);
+ assign(value, get_dpr_dw0(r1));
+
+ s390_cc_thunk_putFZ(S390_CC_OP_DFP_TDC_64, value, op2addr);
+
+ return "tdcdt";
+}
+
+static const HChar *
+s390_irgen_TDCXT(UChar r1, IRTemp op2addr)
+{
+ IRTemp value = newTemp(Ity_D128);
+
+ vassert(s390_host_has_dfp);
+ assign(value, get_dpr_pair(r1));
+
+ s390_cc_thunk_put1d128Z(S390_CC_OP_DFP_TDC_128, value, op2addr);
+
+ return "tdcxt";
+}
+
+static const HChar *
+s390_irgen_TDGET(UChar r1, IRTemp op2addr)
+{
+ IRTemp value = newTemp(Ity_D32);
+
+ vassert(s390_host_has_dfp);
+ assign(value, get_dpr_w0(r1));
+
+ s390_cc_thunk_putFZ(S390_CC_OP_DFP_TDG_32, value, op2addr);
+
+ return "tdget";
+}
+
+static const HChar *
+s390_irgen_TDGDT(UChar r1, IRTemp op2addr)
+{
+ IRTemp value = newTemp(Ity_D64);
+
+ vassert(s390_host_has_dfp);
+ assign(value, get_dpr_dw0(r1));
+
+ s390_cc_thunk_putFZ(S390_CC_OP_DFP_TDG_64, value, op2addr);
+
+ return "tdgdt";
+}
+
+static const HChar *
+s390_irgen_TDGXT(UChar r1, IRTemp op2addr)
+{
+ IRTemp value = newTemp(Ity_D128);
+
+ vassert(s390_host_has_dfp);
+ assign(value, get_dpr_pair(r1));
+
+ s390_cc_thunk_put1d128Z(S390_CC_OP_DFP_TDG_128, value, op2addr);
+
+ return "tdgxt";
+}
+
static const HChar *
s390_irgen_CLC(UChar length, IRTemp start1, IRTemp start2)
{
case 0xb3e4: s390_format_RRE_FF(s390_irgen_CDTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
case 0xb3e5: /* EEDTR */ goto unimplemented;
- case 0xb3e7: /* ESDTR */ goto unimplemented;
+ case 0xb3e7: s390_format_RRE_RF(s390_irgen_ESDTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3e8: /* KXTR */ goto unimplemented;
case 0xb3e9: /* CGXTR */ goto unimplemented;
case 0xb3ea: /* CUXTR */ goto unimplemented;
case 0xb3ec: s390_format_RRE_FF(s390_irgen_CXTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
case 0xb3ed: /* EEXTR */ goto unimplemented;
- case 0xb3ef: /* ESXTR */ goto unimplemented;
+ case 0xb3ef: s390_format_RRE_RF(s390_irgen_ESXTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3f1: /* CDGTR */ goto unimplemented;
case 0xb3f2: /* CDUTR */ goto unimplemented;
case 0xb3f3: /* CDSTR */ goto unimplemented;
case 0xed0000000041ULL: /* SRDT */ goto unimplemented;
case 0xed0000000048ULL: /* SLXT */ goto unimplemented;
case 0xed0000000049ULL: /* SRXT */ goto unimplemented;
- case 0xed0000000050ULL: /* TDCET */ goto unimplemented;
- case 0xed0000000051ULL: /* TDGET */ goto unimplemented;
- case 0xed0000000054ULL: /* TDCDT */ goto unimplemented;
- case 0xed0000000055ULL: /* TDGDT */ goto unimplemented;
- case 0xed0000000058ULL: /* TDCXT */ goto unimplemented;
- case 0xed0000000059ULL: /* TDGXT */ goto unimplemented;
+ 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;
+ case 0xed0000000051ULL: s390_format_RXE_FRRD(s390_irgen_TDGET, ovl.fmt.RXE.r1,
+ ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
+ ovl.fmt.RXE.d2); goto ok;
+ case 0xed0000000054ULL: s390_format_RXE_FRRD(s390_irgen_TDCDT, ovl.fmt.RXE.r1,
+ ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
+ ovl.fmt.RXE.d2); goto ok;
+ case 0xed0000000055ULL: s390_format_RXE_FRRD(s390_irgen_TDGDT, ovl.fmt.RXE.r1,
+ ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
+ ovl.fmt.RXE.d2); goto ok;
+ case 0xed0000000058ULL: s390_format_RXE_FRRD(s390_irgen_TDCXT, ovl.fmt.RXE.r1,
+ ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
+ ovl.fmt.RXE.d2); goto ok;
+ case 0xed0000000059ULL: s390_format_RXE_FRRD(s390_irgen_TDGXT, ovl.fmt.RXE.r1,
+ ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
+ ovl.fmt.RXE.d2); goto ok;
case 0xed0000000064ULL: s390_format_RXY_FRRD(s390_irgen_LEY, ovl.fmt.RXY.r1,
ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
ovl.fmt.RXY.dl2,
break;
}
+ case S390_INSN_DFP_UNOP:
+ addHRegUse(u, HRmWrite, insn->variant.dfp_unop.dst_hi);
+ addHRegUse(u, HRmRead, insn->variant.dfp_unop.op_hi); /* operand */
+ if (insn->size == 16) {
+ addHRegUse(u, HRmWrite, insn->variant.dfp_unop.dst_lo);
+ addHRegUse(u, HRmRead, insn->variant.dfp_unop.op_lo); /* operand */
+ }
+ break;
+
case S390_INSN_DFP_COMPARE:
addHRegUse(u, HRmWrite, insn->variant.dfp_compare.dst);
addHRegUse(u, HRmRead, insn->variant.dfp_compare.op1_hi); /* left */
break;
}
+ case S390_INSN_DFP_UNOP:
+ insn->variant.dfp_unop.dst_hi =
+ lookupHRegRemap(m, insn->variant.dfp_unop.dst_hi);
+ insn->variant.dfp_unop.op_hi =
+ lookupHRegRemap(m, insn->variant.dfp_unop.op_hi);
+ if (insn->size == 16) {
+ insn->variant.dfp_unop.dst_lo =
+ lookupHRegRemap(m, insn->variant.dfp_unop.dst_lo);
+ insn->variant.dfp_unop.op_lo =
+ lookupHRegRemap(m, insn->variant.dfp_unop.op_lo);
+ }
+ break;
+
case S390_INSN_DFP_COMPARE:
insn->variant.dfp_compare.dst =
lookupHRegRemap(m, insn->variant.dfp_compare.dst);
}
+static UChar *
+s390_emit_ESDTR(UChar *p, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC3(MNM, GPR, FPR), "esdtr", r1, r2);
+
+ return emit_RRE(p, 0xb3e70000, r1, r2);
+}
+
+
+static UChar *
+s390_emit_ESXTR(UChar *p, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC3(MNM, GPR, FPR), "esxtr", r1, r2);
+
+ return emit_RRE(p, 0xb3ef0000, r1, r2);
+}
+
+
static UChar *
s390_emit_LDETR(UChar *p, UChar m4, UChar r1, UChar r2)
{
}
+s390_insn *
+s390_insn_dfp_unop(UChar size, s390_dfp_unop_t tag, HReg dst, HReg op)
+{
+ s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+ vassert(size == 8);
+
+ insn->tag = S390_INSN_DFP_UNOP;
+ insn->size = size;
+ insn->variant.dfp_unop.tag = tag;
+ insn->variant.dfp_unop.dst_hi = dst;
+ insn->variant.dfp_unop.op_hi = op;
+ insn->variant.dfp_unop.dst_lo = INVALID_HREG;
+ insn->variant.dfp_unop.op_lo = INVALID_HREG;
+
+ return insn;
+}
+
+
s390_insn *
s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t tag, HReg dst,
HReg op1, HReg op2)
}
+s390_insn *
+s390_insn_dfp128_unop(UChar size, s390_dfp_unop_t tag, HReg dst,
+ HReg op_hi, HReg op_lo)
+{
+ s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+ /* destination is an 8 byte integer value */
+ vassert(size == 8);
+ vassert(is_valid_fp128_regpair(op_hi, op_lo));
+
+ insn->tag = S390_INSN_DFP_UNOP;
+ insn->size = size;
+ insn->variant.dfp_unop.tag = tag;
+ insn->variant.dfp_unop.dst_hi = dst;
+ insn->variant.dfp_unop.dst_lo = INVALID_HREG;
+ insn->variant.dfp_unop.op_hi = op_hi;
+ insn->variant.dfp_unop.op_lo = op_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)
break;
}
+ case S390_INSN_DFP_UNOP:
+ switch (insn->variant.dfp_unop.tag) {
+ case S390_DFP_EXTRACT_SIG_D64:
+ case S390_DFP_EXTRACT_SIG_D128: op = "v-d2sig"; break;
+ default: goto fail;
+ }
+ s390_sprintf(buf, "%M %R,%R", op, insn->variant.dfp_unop.dst_hi,
+ insn->variant.dfp_unop.op_hi);
+ break;
+
case S390_INSN_DFP_COMPARE:
switch (insn->variant.dfp_compare.tag) {
case S390_DFP_COMPARE: op = "v-dcmp"; break;
}
+static UChar *
+s390_insn_dfp_unop_emit(UChar *buf, const s390_insn *insn)
+{
+ UInt r1 = hregNumber(insn->variant.dfp_unop.dst_hi);
+ UInt r2 = hregNumber(insn->variant.dfp_unop.op_hi);
+
+ switch (insn->variant.dfp_unop.tag) {
+ case S390_DFP_EXTRACT_SIG_D64: return s390_emit_ESDTR(buf, r1, r2); break;
+ case S390_DFP_EXTRACT_SIG_D128: return s390_emit_ESXTR(buf, r1, r2); break;
+ default: goto fail;
+ }
+ fail:
+ vpanic("s390_insn_dfp_unop_emit");
+}
+
+
static UChar *
s390_insn_dfp_compare_emit(UChar *buf, const s390_insn *insn)
{
end = s390_insn_dfp_binop_emit(buf, insn);
break;
+ case S390_INSN_DFP_UNOP:
+ end = s390_insn_dfp_unop_emit(buf, insn);
+ break;
+
case S390_INSN_DFP_COMPARE:
end = s390_insn_dfp_compare_emit(buf, insn);
break;
S390_INSN_BFP_COMPARE,
S390_INSN_BFP_CONVERT,
S390_INSN_DFP_BINOP, /* Decimal floating point */
+ S390_INSN_DFP_UNOP,
S390_INSN_DFP_COMPARE,
S390_INSN_DFP_CONVERT,
S390_INSN_MFENCE,
S390_DFP_DIV
} s390_dfp_binop_t;
+/* The kind of unary DFP operations */
+typedef enum {
+ S390_DFP_EXTRACT_SIG_D64,
+ S390_DFP_EXTRACT_SIG_D128,
+} s390_dfp_unop_t;
+
/* The kind of DFP compare operations */
typedef enum {
S390_DFP_COMPARE,
struct {
s390_dfp_binop *details;
} dfp_binop;
+ struct {
+ s390_dfp_unop_t tag;
+ HReg dst_hi; /* 128-bit result high part; 64-bit result */
+ HReg dst_lo; /* 128-bit result low part */
+ HReg op_hi; /* 128-bit operand high part; 64-bit opnd */
+ HReg op_lo; /* 128-bit operand low part */
+ } dfp_unop;
struct {
s390_dfp_conv_t tag;
s390_dfp_round_t rounding_mode;
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_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 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_unop(UChar size, s390_dfp_unop_t, HReg dst,
+ HReg op_hi, HReg op_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);
return dst;
}
+ if (unop == Iop_ExtractSigD64) {
+ dst = newVRegI(env);
+ h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
+ addInstr(env,
+ s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
+ return dst;
+ }
+
+ if (unop == Iop_ExtractSigD128) {
+ HReg op_hi, op_lo, f13, f15;
+ dst = newVRegI(env);
+ s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
+
+ /* We use non-virtual registers r13 and r15 as pair */
+ f13 = make_fpr(13);
+ f15 = make_fpr(15);
+
+ /* operand --> (f13, f15) */
+ addInstr(env, s390_insn_move(8, f13, op_hi));
+ addInstr(env, s390_insn_move(8, f15, op_lo));
+
+ addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
+ dst, f13, f15));
+ return dst;
+ }
+
/* Expressions whose argument is 1-bit wide */
if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
s390_cc_t cond = s390_isel_cc(env, arg);