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)
{
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;
}
+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)
{
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));
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;
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));
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;
}
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;
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;
}
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 */
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 */
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,
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 */
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);
}
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");
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:
/* 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.