return IRExpr_Get(fpr_dw0_offset(archreg), Ity_D64);
}
+/* Read a float of given type from an fpr. */
+static IRExpr *
+get_fpr_float(UInt archreg, IRType type)
+{
+ if (type == Ity_F128)
+ return get_fpr_pair(archreg);
+ else
+ return IRExpr_Get(fpr_offset(archreg), type);
+}
+
/*------------------------------------------------------------*/
/*--- gpr registers ---*/
/*------------------------------------------------------------*/
return "axbr";
}
+/* Helper for "compare" insns CEBR, CDBR, CXBR, and their signalling
+ counterparts. */
static const HChar *
-s390_irgen_CEBR(UChar r1, UChar r2)
+s390_irgen_CxBR(const HChar *mnem, UChar r1, UChar r2, IRType type, IROp cmp_op)
{
- IRTemp op1 = newTemp(Ity_F32);
- IRTemp op2 = newTemp(Ity_F32);
+ IRTemp op1 = newTemp(type);
+ IRTemp op2 = newTemp(type);
IRTemp cc_vex = newTemp(Ity_I32);
IRTemp cc_s390 = newTemp(Ity_I32);
- assign(op1, get_fpr_w0(r1));
- assign(op2, get_fpr_w0(r2));
- assign(cc_vex, binop(Iop_CmpF32, mkexpr(op1), mkexpr(op2)));
+ assign(op1, get_fpr_float(r1, type));
+ assign(op2, get_fpr_float(r2, type));
+ assign(cc_vex, binop(cmp_op, mkexpr(op1), mkexpr(op2)));
assign(cc_s390, convert_vex_bfpcc_to_s390(cc_vex));
s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
+ return mnem;
+}
+
+static const HChar *
+s390_irgen_CEBR(UChar r1, UChar r2)
+{
+ return s390_irgen_CxBR("cebr", r1, r2, Ity_F32, Iop_CmpF32);
+}
- return "cebr";
+static const HChar *
+s390_irgen_KEBR(UChar r1, UChar r2)
+{
+ return s390_irgen_CxBR("kebr", r1, r2, Ity_F32, Iop_CmpF32);
}
static const HChar *
s390_irgen_CDBR(UChar r1, UChar r2)
{
- IRTemp op1 = newTemp(Ity_F64);
- IRTemp op2 = newTemp(Ity_F64);
- IRTemp cc_vex = newTemp(Ity_I32);
- IRTemp cc_s390 = newTemp(Ity_I32);
+ return s390_irgen_CxBR("cdbr", r1, r2, Ity_F64, Iop_CmpF64);
+}
- assign(op1, get_fpr_dw0(r1));
- assign(op2, get_fpr_dw0(r2));
- assign(cc_vex, binop(Iop_CmpF64, mkexpr(op1), mkexpr(op2)));
+static const HChar *
+s390_irgen_KDBR(UChar r1, UChar r2)
+{
+ return s390_irgen_CxBR("kdbr", r1, r2, Ity_F64, Iop_CmpF64);
+}
- assign(cc_s390, convert_vex_bfpcc_to_s390(cc_vex));
- s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
+static const HChar *
+s390_irgen_CXBR(UChar r1, UChar r2)
+{
+ return s390_irgen_CxBR("cxbr", r1, r2, Ity_F128, Iop_CmpF128);
+}
- return "cdbr";
+static const HChar *
+s390_irgen_KXBR(UChar r1, UChar r2)
+{
+ return s390_irgen_CxBR("kxbr", r1, r2, Ity_F128, Iop_CmpF128);
}
+/* Helper for "compare" insns CEB, CDB, and their signalling counterparts. */
static const HChar *
-s390_irgen_CXBR(UChar r1, UChar r2)
+s390_irgen_CxB(const HChar *mnem, UChar r1, IRTemp op2addr, IRType type,
+ IROp cmp_op)
{
- IRTemp op1 = newTemp(Ity_F128);
- IRTemp op2 = newTemp(Ity_F128);
+ IRTemp op1 = newTemp(type);
+ IRTemp op2 = newTemp(type);
IRTemp cc_vex = newTemp(Ity_I32);
IRTemp cc_s390 = newTemp(Ity_I32);
- assign(op1, get_fpr_pair(r1));
- assign(op2, get_fpr_pair(r2));
- assign(cc_vex, binop(Iop_CmpF128, mkexpr(op1), mkexpr(op2)));
+ assign(op1, get_fpr_float(r1, type));
+ assign(op2, load(type, mkexpr(op2addr)));
+ assign(cc_vex, binop(cmp_op, mkexpr(op1), mkexpr(op2)));
assign(cc_s390, convert_vex_bfpcc_to_s390(cc_vex));
s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
-
- return "cxbr";
+ return mnem;
}
static const HChar *
s390_irgen_CEB(UChar r1, IRTemp op2addr)
{
- IRTemp op1 = newTemp(Ity_F32);
- IRTemp op2 = newTemp(Ity_F32);
- IRTemp cc_vex = newTemp(Ity_I32);
- IRTemp cc_s390 = newTemp(Ity_I32);
-
- assign(op1, get_fpr_w0(r1));
- assign(op2, load(Ity_F32, mkexpr(op2addr)));
- assign(cc_vex, binop(Iop_CmpF32, mkexpr(op1), mkexpr(op2)));
-
- assign(cc_s390, convert_vex_bfpcc_to_s390(cc_vex));
- s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
+ return s390_irgen_CxB("ceb", r1, op2addr, Ity_F32, Iop_CmpF32);
+}
- return "ceb";
+static const HChar *
+s390_irgen_KEB(UChar r1, IRTemp op2addr)
+{
+ return s390_irgen_CxB("keb", r1, op2addr, Ity_F32, Iop_CmpF32);
+ return "keb";
}
static const HChar *
s390_irgen_CDB(UChar r1, IRTemp op2addr)
{
- IRTemp op1 = newTemp(Ity_F64);
- IRTemp op2 = newTemp(Ity_F64);
- IRTemp cc_vex = newTemp(Ity_I32);
- IRTemp cc_s390 = newTemp(Ity_I32);
-
- assign(op1, get_fpr_dw0(r1));
- assign(op2, load(Ity_F64, mkexpr(op2addr)));
- assign(cc_vex, binop(Iop_CmpF64, mkexpr(op1), mkexpr(op2)));
-
- assign(cc_s390, convert_vex_bfpcc_to_s390(cc_vex));
- s390_cc_thunk_put1(S390_CC_OP_SET, cc_s390, False);
+ return s390_irgen_CxB("cdb", r1, op2addr, Ity_F64, Iop_CmpF64);
+}
- return "cdb";
+static const HChar *
+s390_irgen_KDB(UChar r1, IRTemp op2addr)
+{
+ return s390_irgen_CxB("kdb", r1, op2addr, Ity_F64, Iop_CmpF64);
}
static const HChar *
case 0xb306: s390_format_RRE_FF(s390_irgen_LXEBR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
case 0xb307: /* MXDBR */ goto unimplemented;
- case 0xb308: /* KEBR */ goto unimplemented;
+ case 0xb308: s390_format_RRE_FF(s390_irgen_KEBR, RRE_r1(ovl),
+ RRE_r2(ovl)); goto ok;
case 0xb309: s390_format_RRE_FF(s390_irgen_CEBR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
case 0xb30a: s390_format_RRE_FF(s390_irgen_AEBR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
case 0xb317: s390_format_RRE_FF(s390_irgen_MEEBR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
- case 0xb318: /* KDBR */ goto unimplemented;
+ case 0xb318: s390_format_RRE_FF(s390_irgen_KDBR, RRE_r1(ovl),
+ RRE_r2(ovl)); goto ok;
case 0xb319: s390_format_RRE_FF(s390_irgen_CDBR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
case 0xb31a: s390_format_RRE_FF(s390_irgen_ADBR, RRE_r1(ovl),
case 0xb347: s390_format_RRF_UUFF(s390_irgen_FIXBRA, RRF2_m3(ovl),
RRF2_m4(ovl), RRF2_r1(ovl),
RRF2_r2(ovl)); goto ok;
- case 0xb348: /* KXBR */ goto unimplemented;
+ case 0xb348: s390_format_RRE_FF(s390_irgen_KXBR, RRE_r1(ovl),
+ RRE_r2(ovl)); goto ok;
case 0xb349: s390_format_RRE_FF(s390_irgen_CXBR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
case 0xb34a: s390_format_RRE_FF(s390_irgen_AXBR, RRE_r1(ovl),
RXE_x2(ovl), RXE_b2(ovl),
RXE_d2(ovl)); goto ok;
case 0xed0000000007ULL: /* MXDB */ goto unimplemented;
- case 0xed0000000008ULL: /* KEB */ goto unimplemented;
+ case 0xed0000000008ULL: s390_format_RXE_FRRD(s390_irgen_KEB, RXE_r1(ovl),
+ RXE_x2(ovl), RXE_b2(ovl),
+ RXE_d2(ovl)); goto ok;
case 0xed0000000009ULL: s390_format_RXE_FRRD(s390_irgen_CEB, RXE_r1(ovl),
RXE_x2(ovl), RXE_b2(ovl),
RXE_d2(ovl)); goto ok;
case 0xed0000000017ULL: s390_format_RXE_FRRD(s390_irgen_MEEB, RXE_r1(ovl),
RXE_x2(ovl), RXE_b2(ovl),
RXE_d2(ovl)); goto ok;
- case 0xed0000000018ULL: /* KDB */ goto unimplemented;
+ case 0xed0000000018ULL: s390_format_RXE_FRRD(s390_irgen_KDB, RXE_r1(ovl),
+ RXE_x2(ovl), RXE_b2(ovl),
+ RXE_d2(ovl)); goto ok;
case 0xed0000000019ULL: s390_format_RXE_FRRD(s390_irgen_CDB, RXE_r1(ovl),
RXE_x2(ovl), RXE_b2(ovl),
RXE_d2(ovl)); goto ok;
#include <stdio.h>
-/* Test BFP comparison for 32/64-bit. */
+static const char *const cmp_result_str[] = {
+ "==", "<", ">", "??"
+};
-void cebr(float v1, float v2)
+#define TEST_CxB(insn, fmt, mode, v1, v2) \
+ do { \
+ int cc; \
+ \
+ __asm__ volatile(insn " %[r1],%[r2]\n\t" \
+ "ipm %[psw]\n\t" \
+ "srl %[psw],28\n\t" \
+ : [psw]"=d"(cc) \
+ : [r1]"f"(v1), [r2]mode(v2) \
+ : "cc"); \
+ printf("%-6s" fmt " %s " fmt "\n", \
+ insn ":", v1, cmp_result_str[cc], v2); \
+ } while (0)
+
+/* Test BFP comparison for 32/64/128-bit. */
+
+static void cebr(float a, float b)
+{
+ TEST_CxB("cebr", "%g", "f", a, b);
+}
+
+static void ceb(float a, float b)
+{
+ TEST_CxB("ceb", "%g", "R", a, b);
+}
+
+static void cdbr(double a, double b)
{
- int cc;
+ TEST_CxB("cdbr", "%g", "f", a, b);
+}
- __asm__ volatile("cebr %[r1],%[r2]\n\t"
- "ipm %[psw]\n\t"
- "srl %[psw],28\n\t"
- : [psw]"=d"(cc) : [r1]"f"(v1), [r2]"f"(v2) : "cc");
- if (cc == 0)
- printf("cfebr: %f == %f\n", v1, v2);
- if (cc == 1)
- printf("cfebr: %f < %f\n", v1, v2);
- if (cc == 2)
- printf("cfebr: %f > %f\n", v1, v2);
+static void cdb(double a, double b)
+{
+ TEST_CxB("cdb", "%g", "R", a, b);
}
-void cdbr(double v1, double v2)
+static void cxbr(long double a, long double b)
{
- int cc;
+ TEST_CxB("cxbr", "%Lg", "f", a, b);
+}
+
+static void kebr(float a, float b)
+{
+ TEST_CxB("kebr", "%g", "f", a, b);
+}
- __asm__ volatile("cdbr %[r1],%[r2]\n\t"
- "ipm %[psw]\n\t"
- "srl %[psw],28\n\t"
- : [psw]"=d"(cc) : [r1]"f"(v1), [r2]"f"(v2) : "cc");
- if (cc == 0)
- printf("cdebr: %f == %f\n", v1, v2);
- if (cc == 1)
- printf("cdebr: %f < %f\n", v1, v2);
- if (cc == 2)
- printf("cdebr: %f > %f\n", v1, v2);
+static void keb(float a, float b)
+{
+ TEST_CxB("keb", "%g", "R", a, b);
+}
+
+static void kdbr(double a, double b)
+{
+ TEST_CxB("kdbr", "%g", "f", a, b);
+}
+
+static void kdb(double a, double b)
+{
+ TEST_CxB("kdb", "%g", "R", a, b);
+}
+
+static void kxbr(long double a, long double b)
+{
+ TEST_CxB("kxbr", "%Lg", "f", a, b);
+}
+
+static void do_compare(float a, float b)
+{
+ cebr(a, b);
+ ceb(a, b);
+ kebr(a, b);
+ keb(a, b);
+ cdbr((double) a, (double) b);
+ cdb((double) a, (double) b);
+ kdbr((double) a, (double) b);
+ kdb((double) a, (double) b);
+ cxbr((long double) a, (long double) b);
+ kxbr((long double) a, (long double) b);
}
int main(void)
{
- float f1, f2;
- float d1, d2;
-
- // compare 4 bytes
- f1 = 3.14f;
- f2 = f1;
- cebr(f1, f2);
- f2 = f1 + 10.;
- cebr(f1, f2);
- f2 = f1 - 100.;
- cebr(f1, f2);
-
- // compare 8 bytes
- d1 = 2.78;
- d2 = d1;
- cdbr(d1, d2);
- d2 = d1 + 10.;
- cdbr(d1, d2);
- d2 = d1 - 100.;
- cdbr(d1, d2);
+ float inf = 1.f / 0.;
+ float neg_inf = -1.f / 0.;
+ do_compare(3.14f, 3.14f);
+ do_compare(-2.78f, 2.78f);
+ do_compare(inf, inf);
+ do_compare(inf, neg_inf);
+ do_compare(neg_inf, neg_inf);
+ do_compare(inf, 1.f);
+ do_compare(neg_inf, -1.f);
+ do_compare(1.f / inf, -1.f / inf);
return 0;
}