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)
{
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;
}
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 */
}
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);
}
+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)
{
}
+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)
{
}
+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)
}
+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)
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;
}
+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)
{
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;
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,
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,
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;
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,
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);
/* --------- 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;
}
rounding_mode));
return dst;
}
- default:
- goto irreducible;
case Iop_D128toD64: {
HReg op_hi, op_lo, f13, f15;
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;
}
}