]> 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/bfp-diint
 /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);
+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);
index f5e826714547c04874619ed5b1e78720ec5ddf0d..11ef80a3d171dd31ef2dd56a14e4dd43307494f8 100644 (file)
@@ -2586,6 +2586,49 @@ s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state,
 
 #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 ---*/
 /*---------------------------------------------------------------*/
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)));
 }
 
+
+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)
 {
@@ -18686,13 +18724,17 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
                 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 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;
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,
-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,
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 \
-             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 \
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");
 
-    # 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");
index ab3c93aa9e159383b91ef5620a6a981c95b5a6c8..c29a4ff22c4d54cbfed60dd9ccd4bfd4fceb0b95 100644 (file)
@@ -1,6 +1,6 @@
 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
-Total: 154451 tests generated
+Total: 154465 tests generated
 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)",
-   // 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}",