]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Bug 416301 - s390x: Support "compare and signal" instructions
authorAndreas Arnez <arnez@linux.ibm.com>
Thu, 16 Jan 2020 12:49:10 +0000 (13:49 +0100)
committerAndreas Arnez <arnez@linux.ibm.com>
Thu, 6 Feb 2020 11:28:19 +0000 (12:28 +0100)
Add VEX support for the s390x "compare and signal" instructions KEBR,
KDBR, KXBR, KEB, and KDB.  For now, let them behave exactly like their
non-signalling counterparts.  Enhance the bfp-4 test case to cover these
instructions as well.  Update the list of supported instructions in
s390-opcodes.csv.  Add a disclaimer to README.s390, explaining that FP
signalling is not handled accurately on s390x at the moment.

NEWS
README.s390
VEX/priv/guest_s390_toIR.c
docs/internals/s390-opcodes.csv
none/tests/s390x/bfp-4.c
none/tests/s390x/bfp-4.stdout.exp

diff --git a/NEWS b/NEWS
index 96ed2ffd902da80e933f8c572b1a76df853f4acc..c9ec9fafb08891ff1f42d4f8f6ec0cb34352775c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -105,6 +105,7 @@ where XXXXXX is the bug number as listed below.
 415757  vex x86->IR: 0x66 0xF 0xCE 0x4F (bswapw)
 416239  valgrind crashes when handling clock_adjtime
 416286  DRD reports "conflicting load" error on std::mutex::lock()
+416301  s390x: "compare and signal" not supported
 416387  finit_module and bpf syscalls are unhandled on arm64
 416464  Fix false reports for uninitialized memory for PR_CAPBSET_READ/DROP
 n-i-bz  Fix minor one time leaks in dhat.
index ac9485a6258f964b5cacd7974ed6d257319dd1d6..7df386ef4183b2c16e53fada5d8fdab3dc935fa3 100644 (file)
@@ -11,7 +11,10 @@ Limitations
 -----------
 - 31-bit client programs are not supported.
 - Hexadecimal floating point is not supported.
-- Transactional memory is not supported.
+- Transactional memory is not supported. The transactional-execution
+  facility is masked off from HWCAP.
+- FP signalling is not accurate. E.g., the "compare and signal"
+  instructions behave like their non-signalling counterparts.
 - memcheck, cachegrind, drd, helgrind, massif, lackey, and none are
   supported. 
 - On machine models predating z10, cachegrind will assume a z10 cache
@@ -21,8 +24,6 @@ Limitations
 - Some gcc versions use mvc to copy 4/8 byte values. This will affect
   certain debug messages. For example, memcheck will complain about
   4 one-byte reads/writes instead of just a single read/write.
-- The transactional-execution facility is not supported; it is masked
-  off from HWCAP.
 
 
 Hardware facilities
index a8f0d3a074676e8db2b6f8c35a69fc16be49ea9e..ed95fc04215b54ff1ccca8819535ca0a4e506fa7 100644 (file)
@@ -1204,6 +1204,16 @@ get_dpr_dw0(UInt archreg)
    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                                        ---*/
 /*------------------------------------------------------------*/
@@ -14055,94 +14065,103 @@ s390_irgen_AXBR(UChar r1, UChar r2)
    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 *
@@ -19270,7 +19289,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
    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),
@@ -19300,7 +19320,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
                                    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),
@@ -19351,7 +19372,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
    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),
@@ -21408,7 +21430,9 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
                                                 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;
@@ -21448,7 +21472,9 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
    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;
index 0765bd1e81c7016db88c81f9c05b903d0abf48bb..82332e4ff856a2a88e7d20508791f9c4413b1e31 100644 (file)
@@ -268,11 +268,11 @@ cdbr,"compare long bfp",implemented,
 cdb,"compare long bfp",implemented,
 cebr,"compare short bfp",implemented,
 ceb,"compare short bfp",implemented,
-kxbr,"compare and signal extended bfp","not implemented",
-kdbr,"compare and signal long bfp","not implemented",
-kdb,"compare and signal long bfp","not implemented",
-kebr,"compare and signal short bfp","not implemented",
-keb,"compare and signal short bfp","not implemented",
+kxbr,"compare and signal extended bfp",implemented,
+kdbr,"compare and signal long bfp",implemented,
+kdb,"compare and signal long bfp",implemented,
+kebr,"compare and signal short bfp",implemented,
+keb,"compare and signal short bfp",implemented,
 cxfbr,"convert from fixed 32 to extended bfp",implemented,
 cdfbr,"convert from fixed 32 to long bfp",implemented,
 cefbr,"convert from fixed 32 to short bfp",implemented,
index c2d88818c76c250d3f7e7d4f97e6505d698c0874..02315b6f9ddbbe5ad572b011763a44093202a19e 100644 (file)
 #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;
 }
index eff1366548607c577d25703978c5b1d1283a7577..bc81ea6ceceaf6cbb3f2466299d9a50efcc4e2f0 100644 (file)
@@ -1,6 +1,80 @@
-cfebr:  3.140000 == 3.140000
-cfebr:  3.140000 < 13.140000
-cfebr:  3.140000 > -96.860001
-cdebr:  2.780000 == 2.780000
-cdebr:  2.780000 < 12.780000
-cdebr:  2.780000 > -97.220001
+cebr: 3.14 == 3.14
+ceb:  3.14 == 3.14
+kebr: 3.14 == 3.14
+keb:  3.14 == 3.14
+cdbr: 3.14 == 3.14
+cdb:  3.14 == 3.14
+kdbr: 3.14 == 3.14
+kdb:  3.14 == 3.14
+cxbr: 3.14 == 3.14
+kxbr: 3.14 == 3.14
+cebr: -2.78 < 2.78
+ceb:  -2.78 < 2.78
+kebr: -2.78 < 2.78
+keb:  -2.78 < 2.78
+cdbr: -2.78 < 2.78
+cdb:  -2.78 < 2.78
+kdbr: -2.78 < 2.78
+kdb:  -2.78 < 2.78
+cxbr: -2.78 < 2.78
+kxbr: -2.78 < 2.78
+cebr: inf == inf
+ceb:  inf == inf
+kebr: inf == inf
+keb:  inf == inf
+cdbr: inf == inf
+cdb:  inf == inf
+kdbr: inf == inf
+kdb:  inf == inf
+cxbr: inf == inf
+kxbr: inf == inf
+cebr: inf > -inf
+ceb:  inf > -inf
+kebr: inf > -inf
+keb:  inf > -inf
+cdbr: inf > -inf
+cdb:  inf > -inf
+kdbr: inf > -inf
+kdb:  inf > -inf
+cxbr: inf > -inf
+kxbr: inf > -inf
+cebr: -inf == -inf
+ceb:  -inf == -inf
+kebr: -inf == -inf
+keb:  -inf == -inf
+cdbr: -inf == -inf
+cdb:  -inf == -inf
+kdbr: -inf == -inf
+kdb:  -inf == -inf
+cxbr: -inf == -inf
+kxbr: -inf == -inf
+cebr: inf > 1
+ceb:  inf > 1
+kebr: inf > 1
+keb:  inf > 1
+cdbr: inf > 1
+cdb:  inf > 1
+kdbr: inf > 1
+kdb:  inf > 1
+cxbr: inf > 1
+kxbr: inf > 1
+cebr: -inf < -1
+ceb:  -inf < -1
+kebr: -inf < -1
+keb:  -inf < -1
+cdbr: -inf < -1
+cdb:  -inf < -1
+kdbr: -inf < -1
+kdb:  -inf < -1
+cxbr: -inf < -1
+kxbr: -inf < -1
+cebr: 0 == -0
+ceb:  0 == -0
+kebr: 0 == -0
+keb:  0 == -0
+cdbr: 0 == -0
+cdb:  0 == -0
+kdbr: 0 == -0
+kdb:  0 == -0
+cxbr: 0 == -0
+kxbr: 0 == -0