]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Implement DIDBR and DIEBR instructions master
authorAndreas Arnez <arnez@linux.ibm.com>
Thu, 6 Aug 2026 17:32:38 +0000 (19:32 +0200)
committerAndreas Arnez <arnez@linux.ibm.com>
Thu, 6 Aug 2026 17:48:03 +0000 (19:48 +0200)
The "divide to integer" instructions DIEBR/DIDBR are not implemented.  Fix
this using dirty helpers.

12 files changed:
.gitignore
VEX/priv/guest_s390_defs.h
VEX/priv/guest_s390_helpers.c
VEX/priv/guest_s390_toIR.c
docs/internals/s390-opcodes.csv
none/tests/s390x/Makefile.am
none/tests/s390x/bfp-diint.c [new file with mode: 0644]
none/tests/s390x/bfp-diint.stdout.exp [new file with mode: 0644]
none/tests/s390x/bfp-diint.vgtest [new file with mode: 0644]
none/tests/s390x/bfp-emit.pl
none/tests/s390x/disasm-test/disasm-test.post.exp
none/tests/s390x/disasm-test/opcode.c

index 93221a49e5e34057ede1f225af9328978c09e40d..7d6c5a622efc41e42b188f81d18da7cd0d2c84d6 100644 (file)
 /none/tests/s390x/ecag
 /none/tests/s390x/bfp-306054
 /none/tests/s390x/bfp-arith
 /none/tests/s390x/ecag
 /none/tests/s390x/bfp-306054
 /none/tests/s390x/bfp-arith
+/none/tests/s390x/bfp-diint
 /none/tests/s390x/bfp-load
 /none/tests/s390x/bfp-fpc
 /none/tests/s390x/bfp-tdc
 /none/tests/s390x/bfp-load
 /none/tests/s390x/bfp-fpc
 /none/tests/s390x/bfp-tdc
index 1d3a2be94deb02d733c0a507afe31bc2900c94bd..5c87d2bd948676683b8b2b4f5f2bea87bf1c052a 100644 (file)
@@ -77,6 +77,7 @@ ULong s390x_dirtyhelper_STCKE(ULong *addr);
 void  s390x_dirtyhelper_CUxy(UChar *addr, ULong data, ULong num_bytes);
 ULong s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state,
                                ULong details);
 void  s390x_dirtyhelper_CUxy(UChar *addr, ULong data, ULong num_bytes);
 ULong s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state,
                                ULong details);
+ULong s390x_dirtyhelper_DIxBR(VexGuestS390XState *guest_state, ULong packed);
 ULong s390_do_cu12_cu14_helper1(UInt byte1, UInt etf3_and_m3_is_1);
 ULong s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
                            ULong stuff);
 ULong s390_do_cu12_cu14_helper1(UInt byte1, UInt etf3_and_m3_is_1);
 ULong s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
                            ULong stuff);
index f5e826714547c04874619ed5b1e78720ec5ddf0d..11ef80a3d171dd31ef2dd56a14e4dd43307494f8 100644 (file)
@@ -2586,6 +2586,49 @@ s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state,
 
 #endif
 
 
 #endif
 
+/*------------------------------------------------------------*/
+/*--- Dirty helper for DIEBR/DIDBR instructions            ---*/
+/*------------------------------------------------------------*/
+
+#if defined(VGA_s390x)
+
+ULong
+s390x_dirtyhelper_DIxBR(VexGuestS390XState *guest_state, ULong args)
+{
+   UInt r1 = (args >> 0) & 0xf;
+   UInt r2 = (args >> 4) & 0xf;
+   UInt r3 = (args >> 8) & 0xf;
+   UInt m4 = (args >> 12) & 0xf;
+   UInt op = (args >> 16) & 0xffff;
+   UInt cc;
+
+   V128* gv = &guest_state->guest_v0;
+
+   /* DIEBR/DIDBR instruction to be targeted by EX */
+   UInt insn = (op << 16) | (4u << 12) | ((UInt)m4 << 8) | (0u << 4) | 2u;
+
+   __asm__("ld  %%f0, %[op1]\n\t"
+           "ld  %%f2, %[op2]\n\t"
+           "ld  %%f4, %[op3]\n\t"
+           "ex  %%r0, %[insn]\n\t"
+           "std %%f0, %[op1]\n\t"
+           "std %%f4, %[op3]\n\t"
+           "ipm %[cc]\n\t"
+           : [op1] "+R"(gv[r1]), [op3] "=R"(gv[r3]), [cc] "=d"(cc)
+           : [op2] "R"(gv[r2]), [insn] "R"(insn)
+           : "cc", "f0", "f2", "f4");
+
+   return cc >> 28;
+}
+
+#else
+
+ULong
+s390x_dirtyhelper_DIxBR(VexGuestS390XState *guest_state, ULong packed)
+{ return 0; }
+
+#endif
+
 /*---------------------------------------------------------------*/
 /*--- end                                guest_s390_helpers.c ---*/
 /*---------------------------------------------------------------*/
 /*---------------------------------------------------------------*/
 /*--- end                                guest_s390_helpers.c ---*/
 /*---------------------------------------------------------------*/
index e8305903ecb00aac41b5cc0ba40137f486968ff0..87d7aeb544d0638f548c0220d2c28e7d16699b95 100644 (file)
@@ -12775,6 +12775,44 @@ s390_irgen_LXEB(UChar r1, IRTemp op2addr)
    put_fpr_pair(r1, unop(Iop_F32toF128, mkexpr(op)));
 }
 
    put_fpr_pair(r1, unop(Iop_F32toF128, mkexpr(op)));
 }
 
+
+static void
+s390_irgen_DIxBR(UChar r1, UChar r3, UChar r2, UChar m4, ULong op)
+{
+   s390_insn_assert(is_valid_rounding_mode(m4));
+   IRTemp cc   = newTemp(Ity_I64);
+   ULong  args = (op << 16) | ((ULong)m4 << 12) | ((ULong)r3 << 8) |
+                ((ULong)r2 << 4) | (ULong)r1;
+   IRDirty* d  = unsafeIRDirty_1_N(cc, 0, "s390x_dirtyhelper_DIxBR",
+                                   &s390x_dirtyhelper_DIxBR,
+                                   mkIRExprVec_2(IRExpr_GSPTR(), mkU64(args)));
+   d->nFxState = 3;
+   vex_bzero(&d->fxState, sizeof(d->fxState));
+   d->fxState[0].fx     = Ifx_Read;
+   d->fxState[0].offset = fpr_w0_offset(r2);
+   d->fxState[0].size   = sizeof(UInt);
+   d->fxState[1].fx     = Ifx_Modify;
+   d->fxState[1].offset = fpr_w0_offset(r1);
+   d->fxState[1].size   = sizeof(UInt);
+   d->fxState[2].fx     = Ifx_Write;
+   d->fxState[2].offset = fpr_w0_offset(r3);
+   d->fxState[2].size   = sizeof(UInt);
+   stmt(IRStmt_Dirty(d));
+   s390_cc_set(cc);
+}
+
+static void
+s390_irgen_DIEBR(UChar r1, UChar r3, UChar r2, UChar m4)
+{
+   s390_irgen_DIxBR(r1, r3, r2, m4, 0xb353);
+}
+
+static void
+s390_irgen_DIDBR(UChar r1, UChar r3, UChar r2, UChar m4)
+{
+   s390_irgen_DIxBR(r1, r3, r2, m4, 0xb35b);
+}
+
 static void
 s390_irgen_FIEBRA(UChar m3, UChar m4, UChar r1, UChar r2)
 {
 static void
 s390_irgen_FIEBRA(UChar m3, UChar m4, UChar r1, UChar r2)
 {
@@ -18686,13 +18724,17 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
                 goto ok;
    case 0xb350: /* TBEDR */ goto unimplemented;
    case 0xb351: /* TBDR */ goto unimplemented;
                 goto ok;
    case 0xb350: /* TBEDR */ goto unimplemented;
    case 0xb351: /* TBDR */ goto unimplemented;
-   case 0xb353: /* DIEBR */ goto unimplemented;
+   case 0xb353: s390_irgen_DIEBR(RRFb_r1(ovl), RRFb_r3(ovl), RRFb_r2(ovl),
+                                 RRFb_m4(ovl));
+                goto ok;
    case 0xb357: s390_irgen_FIEBRA(RRFe_m3(ovl), RRFe_m4(ovl), RRFe_r1(ovl),
                                   RRFe_r2(ovl));
                 goto ok;
    case 0xb358: /* THDER */ goto unimplemented;
    case 0xb359: /* THDR */ goto unimplemented;
    case 0xb357: s390_irgen_FIEBRA(RRFe_m3(ovl), RRFe_m4(ovl), RRFe_r1(ovl),
                                   RRFe_r2(ovl));
                 goto ok;
    case 0xb358: /* THDER */ goto unimplemented;
    case 0xb359: /* THDR */ goto unimplemented;
-   case 0xb35b: /* DIDBR */ goto unimplemented;
+   case 0xb35b: s390_irgen_DIDBR(RRFb_r1(ovl), RRFb_r3(ovl), RRFb_r2(ovl),
+                                 RRFb_m4(ovl));
+                goto ok;
    case 0xb35f: s390_irgen_FIDBRA(RRFe_m3(ovl), RRFe_m4(ovl), RRFe_r1(ovl),
                                   RRFe_r2(ovl));
                 goto ok;
    case 0xb35f: s390_irgen_FIDBRA(RRFe_m3(ovl), RRFe_m4(ovl), RRFe_r1(ovl),
                                   RRFe_r2(ovl));
                 goto ok;
index 08620375d03c32b84020636443fd9c942ade9e6d..3420babeea96d0941afe431ad056e034e8dfb24c 100644 (file)
@@ -284,8 +284,8 @@ ddbr,"divide long bfp",implemented,
 ddb,"divide long bfp",implemented,
 debr,"divide short bfp",implemented,
 deb,"divide short bfp",implemented,
 ddb,"divide long bfp",implemented,
 debr,"divide short bfp",implemented,
 deb,"divide short bfp",implemented,
-didbr,"divide to integer long bfp","not implemented",
-diebr,"divide to integer short bfp","not implemented",
+didbr,"divide to integer long bfp",implemented,
+diebr,"divide to integer short bfp",implemented,
 efpc,"extract fpc",implemented,
 ltxbr,"load and test extended bfp",implemented,
 ltdbr,"load and test long bfp",implemented,
 efpc,"extract fpc",implemented,
 ltxbr,"load and test extended bfp",implemented,
 ltdbr,"load and test long bfp",implemented,
index 57ac4d1a9e186d7fdb35d0fc7c9d496cdf839c79..c90a2e0e98ed3202b69096da46e66c58fa3a730a 100644 (file)
@@ -10,7 +10,7 @@ INSN_TESTS = clc clcle cvb cvd icm lpr lam_stam xc mvst add sub mul \
              cs csg cds cdsg cu21 cu21_1 cu24 cu24_1 cu42 cu12 cu12_1 \
              ex_sig ex_clone cu14 cu14_1 cu41 ecag \
              bfp-fpc bfp-306054 \
              cs csg cds cdsg cu21 cu21_1 cu24 cu24_1 cu42 cu12 cu12_1 \
              ex_sig ex_clone cu14 cu14_1 cu41 ecag \
              bfp-fpc bfp-306054 \
-             bfp-muldiv comp-1 comp-2 exrl tmll tm stmg \
+             bfp-muldiv bfp-diint comp-1 comp-2 exrl tmll tm stmg \
             ex clst mvc test_fork test_sig rxsbg popcnt popcnt-mi3 \
             high-word traps \
             spechelper-alr spechelper-algr \
             ex clst mvc test_fork test_sig rxsbg popcnt popcnt-mi3 \
             high-word traps \
             spechelper-alr spechelper-algr \
diff --git a/none/tests/s390x/bfp-diint.c b/none/tests/s390x/bfp-diint.c
new file mode 100644 (file)
index 0000000..4b58c40
--- /dev/null
@@ -0,0 +1,57 @@
+/* Test "divide to integer" instructions. */
+
+#include <math.h>
+#include <stdio.h>
+
+#define GEN_DIXBR(insn, type, m4)                                              \
+   static void insn##_##m4(type dividend, type divisor)                        \
+   {                                                                           \
+      type     op1 = dividend;                                                 \
+      type     op2 = divisor;                                                  \
+      type     op3;                                                            \
+      unsigned cc;                                                             \
+                                                                               \
+      __asm__(#insn " %[r1],%[r3],%[r2]," #m4 "\n\t"                           \
+                    "ipm   %[cc]\n\t"                                          \
+                    "srl   %[cc],28\n\t"                                       \
+              : [r1] "+&f"(op1), [r3] "=&f"(op3), [cc] "=d"(cc)                \
+              : [r2] "f"(op2)                                                  \
+              : "cc");                                                         \
+      printf("\t%g / %g = %g  rem=%g  cc=%u\n", dividend, divisor, op3, op1,   \
+             cc);                                                              \
+   }
+
+GEN_DIXBR(diebr, float, 5);
+GEN_DIXBR(didbr, double, 1);
+GEN_DIXBR(didbr, double, 4);
+GEN_DIXBR(didbr, double, 5);
+GEN_DIXBR(didbr, double, 6);
+
+static const double data[][2] = {{7, 2},        {-6, 2},     {-5, INFINITY},
+                                 {INFINITY, 3}, {5, 0},      {NAN, 3},
+                                 {3, NAN},      {1.5e-45, 1}, {5, 1e-40}};
+
+enum { n_data = sizeof(data) / sizeof(data[0]) };
+
+int main(void)
+{
+   puts("diebr (m4=5)");
+   for (int i = 0; i < n_data; i++)
+      diebr_5(data[i][0], data[i][1]);
+
+   puts("didbr (m4=5)");
+   for (int i = 0; i < n_data; i++)
+      didbr_5(data[i][0], data[i][1]);
+
+   puts("didbr (m4=1)");        /* ties away from zero */
+   didbr_1(5, 2);
+   didbr_1(-5, 2);
+   puts("didbr (m4=4)");        /* ties to even */
+   didbr_4(7, 4);
+   didbr_4(5, 2);
+   puts("didbr (m4=6)");        /* toward +inf */
+   didbr_6(5, 2);
+   didbr_6(5, -2);
+
+   return 0;
+}
diff --git a/none/tests/s390x/bfp-diint.stdout.exp b/none/tests/s390x/bfp-diint.stdout.exp
new file mode 100644 (file)
index 0000000..4841112
--- /dev/null
@@ -0,0 +1,29 @@
+diebr (m4=5)
+       7 / 2 = 3  rem=1  cc=0
+       -6 / 2 = -3  rem=-0  cc=0
+       -5 / inf = -0  rem=-5  cc=0
+       inf / 3 = nan  rem=nan  cc=1
+       5 / 0 = nan  rem=nan  cc=1
+       nan / 3 = nan  rem=nan  cc=1
+       3 / nan = nan  rem=nan  cc=1
+       1.4013e-45 / 1 = 0  rem=1.4013e-45  cc=0
+       5 / 9.99995e-41 = 7.9655e-18  rem=3.24493e-07  cc=3
+didbr (m4=5)
+       7 / 2 = 3  rem=1  cc=0
+       -6 / 2 = -3  rem=-0  cc=0
+       -5 / inf = -0  rem=-5  cc=0
+       inf / 3 = nan  rem=nan  cc=1
+       5 / 0 = nan  rem=nan  cc=1
+       nan / 3 = nan  rem=nan  cc=1
+       3 / nan = nan  rem=nan  cc=1
+       1.5e-45 / 1 = 0  rem=1.5e-45  cc=0
+       5 / 1e-40 = 5e+40  rem=3.22535e-16  cc=2
+didbr (m4=1)
+       5 / 2 = 3  rem=-1  cc=0
+       -5 / 2 = -3  rem=1  cc=0
+didbr (m4=4)
+       7 / 4 = 2  rem=-1  cc=0
+       5 / 2 = 2  rem=1  cc=0
+didbr (m4=6)
+       5 / 2 = 3  rem=-1  cc=0
+       5 / -2 = -2  rem=1  cc=0
diff --git a/none/tests/s390x/bfp-diint.vgtest b/none/tests/s390x/bfp-diint.vgtest
new file mode 100644 (file)
index 0000000..55db0d0
--- /dev/null
@@ -0,0 +1,2 @@
+prog: bfp-diint
+vgopts: -q
index b40e10a05acaa1907558947035c1c2d2b2d737c5..c79dbf00042c41da39ea2f8974f7ea08559cc40a 100755 (executable)
@@ -202,7 +202,7 @@ sub main
     test_insn("ddbr %f0,%f1");
     test_insn("dxbr %f0,%f1");
 
     test_insn("ddbr %f0,%f1");
     test_insn("dxbr %f0,%f1");
 
-    # echo "DIVIDE TO INTEGER"    not implemented
+    # echo "DIVIDE TO INTEGER"    implemented via dirty helper
     # echo "LOAD AND TEST"        insn not mapped one-to-one
 
     header("LOAD COMPLEMENT");
     # echo "LOAD AND TEST"        insn not mapped one-to-one
 
     header("LOAD COMPLEMENT");
index ab3c93aa9e159383b91ef5620a6a981c95b5a6c8..c29a4ff22c4d54cbfed60dd9ccd4bfd4fceb0b95 100644 (file)
@@ -1,6 +1,6 @@
 Looking for missed specification exceptions
 Looking for missed specification exceptions
-Total:  43957 tests generated
-Total:  43957 specification exceptions
+Total:  43975 tests generated
+Total:  43975 specification exceptions
 Looking for unexpected specification exceptions
 Looking for unexpected specification exceptions
-Total: 154451 tests generated
+Total: 154465 tests generated
 Total:      0 specification exceptions
 Total:      0 specification exceptions
index 0e41ab0c8611bfd5f25b7bc587cd0c391d2d9bdb..5700741b34e2e2c33b821caf6d6038d75901fb84 100644 (file)
@@ -1047,8 +1047,8 @@ static const char *opcodes[] = {
    "dxbr    f1:{0,1,4,5,8,9,12,13},f2:{0,1,4,5,8,9,12,13}",
    "deb     f1,d12(x2,b2)",
    "ddb     f1,d12(x2,b2)",
    "dxbr    f1:{0,1,4,5,8,9,12,13},f2:{0,1,4,5,8,9,12,13}",
    "deb     f1,d12(x2,b2)",
    "ddb     f1,d12(x2,b2)",
-   // diebr  not implemented
-   // didbr  not implemented
+   "diebr   f1,f3,f2,m4:{0,1,3,4,5,6,7}",
+   "didbr   f1,f3,f2,m4:{0,1,3,4,5,6,7}",
    "ltebr   f1,f2",
    "ltdbr   f1,f2",
    "ltxbr   f1:{0,1,4,5,8,9,12,13},f2:{0,1,4,5,8,9,12,13}",
    "ltebr   f1,f2",
    "ltdbr   f1,f2",
    "ltxbr   f1:{0,1,4,5,8,9,12,13},f2:{0,1,4,5,8,9,12,13}",