From: Andreas Arnez Date: Thu, 6 Aug 2026 17:32:38 +0000 (+0200) Subject: s390x: Implement DIDBR and DIEBR instructions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;ds=inline;p=thirdparty%2Fvalgrind.git s390x: Implement DIDBR and DIEBR instructions The "divide to integer" instructions DIEBR/DIDBR are not implemented. Fix this using dirty helpers. --- diff --git a/.gitignore b/.gitignore index 93221a49e..7d6c5a622 100644 --- a/.gitignore +++ b/.gitignore @@ -2202,6 +2202,7 @@ /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 diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index 1d3a2be94..5c87d2bd9 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -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); diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index f5e826714..11ef80a3d 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -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 ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index e8305903e..87d7aeb54 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -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; diff --git a/docs/internals/s390-opcodes.csv b/docs/internals/s390-opcodes.csv index 08620375d..3420babee 100644 --- a/docs/internals/s390-opcodes.csv +++ b/docs/internals/s390-opcodes.csv @@ -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, diff --git a/none/tests/s390x/Makefile.am b/none/tests/s390x/Makefile.am index 57ac4d1a9..c90a2e0e9 100644 --- a/none/tests/s390x/Makefile.am +++ b/none/tests/s390x/Makefile.am @@ -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 index 000000000..4b58c403d --- /dev/null +++ b/none/tests/s390x/bfp-diint.c @@ -0,0 +1,57 @@ +/* Test "divide to integer" instructions. */ + +#include +#include + +#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 index 000000000..48411126d --- /dev/null +++ b/none/tests/s390x/bfp-diint.stdout.exp @@ -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 index 000000000..55db0d039 --- /dev/null +++ b/none/tests/s390x/bfp-diint.vgtest @@ -0,0 +1,2 @@ +prog: bfp-diint +vgopts: -q diff --git a/none/tests/s390x/bfp-emit.pl b/none/tests/s390x/bfp-emit.pl index b40e10a05..c79dbf000 100755 --- a/none/tests/s390x/bfp-emit.pl +++ b/none/tests/s390x/bfp-emit.pl @@ -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"); diff --git a/none/tests/s390x/disasm-test/disasm-test.post.exp b/none/tests/s390x/disasm-test/disasm-test.post.exp index ab3c93aa9..c29a4ff22 100644 --- a/none/tests/s390x/disasm-test/disasm-test.post.exp +++ b/none/tests/s390x/disasm-test/disasm-test.post.exp @@ -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 diff --git a/none/tests/s390x/disasm-test/opcode.c b/none/tests/s390x/disasm-test/opcode.c index 0e41ab0c8..5700741b3 100644 --- a/none/tests/s390x/disasm-test/opcode.c +++ b/none/tests/s390x/disasm-test/opcode.c @@ -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}",