From 87a9eae8dde0afd0c39eca80dbabfcb8b26ee0f6 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Sat, 6 Feb 2021 17:18:05 +0530 Subject: [PATCH] arch-power: Add doubleword divide-extended instructions This introduces 128-bit division helpers for adds the following instructions. * Divide Doubleword Extended (divde[o][.]) * Divide Doubleword Extended Unsigned (divdeu[o][.]) Change-Id: I3591d91f22df2dce74fed5147d5de2ce82a83642 Signed-off-by: Sandipan Das --- src/arch/power/insts/integer.hh | 94 +++++++++++++++++++++++++++++++++ src/arch/power/isa/decoder.isa | 26 +++++++++ 2 files changed, 120 insertions(+) diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index 366d36adb..38c0dd0d3 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -285,6 +285,100 @@ class IntArithOp : public IntOp return std::make_tuple(rlo, rhi); } + /** + * Compute overflow, 64-bit quotient and 64-bit remainder of + * 128-bit by 64-bit unsigned integer division based on + * https://codereview.stackexchange.com/a/71013 + */ + inline std::tuple + divide(uint64_t ralo, uint64_t rahi, uint64_t rb) const + { + bool ov; + uint64_t q, r; + #if defined(__SIZEOF_INT128__) + if (rb == 0) { + ov = true; + } else { + __uint128_t ra = ((__uint128_t)rahi << 64) | ralo; + __uint128_t res = ra / rb; + q = res; + r = ra % rb; + ov = res > UINT64_MAX; + } + #else + uint64_t c = 0; + + if (rb == 0) { + ov = true; + } else if (rahi == 0) { + q = ralo / rb; + r = ralo % rb; + ov = false; + } else if (rahi >= rb) { + ov = true; + } else { + for (int i = 0; i < 64; ++i) { + c = rahi >> 63; + rahi = (rahi << 1) | (ralo >> 63); + if (c || (rahi >= rb)) { + rahi -= rb; + c = 1; + } else { + c = 0; + } + ralo = (ralo << 1) | c; + } + q = ralo; + r = rahi; + ov = false; + } + #endif + return std::make_tuple(ov, q, r); + } + + /** + * Compute overflow, 64-bit quotient and 64-bit remainder of + * 128-bit by 64-bit signed integer division + */ + inline std::tuple + divide(uint64_t ralo, int64_t rahi, int64_t rb) const + { + bool ov; + int64_t q, r; + #if defined(__SIZEOF_INT128__) + if (rb == 0) { + ov = true; + } else { + __int128_t ra = ((__int128_t)rahi << 64) | ralo; + __int128_t res = ra / rb; + q = res; + r = ra % rb; + ov = res != q; + } + #else + bool raneg = rahi < 0; + bool rbneg = rb < 0; + + if (raneg) { + ralo = ~(ralo); + rahi = ~(rahi); + if (ralo == -1ULL) { + ralo = 0; + rahi++; + } else { + ralo++; + } + } + + if (rbneg) rb = -rb; + std::tie(ov, q, r) = divide(ralo, (uint64_t)rahi, (uint64_t)rb); + if (raneg ^ rbneg) q = -q; + if (raneg) r = -r; + if (!ov) ov = ((q < 0) ^ (raneg ^ rbneg)); + #endif + return std::make_tuple(ov, q, r); + } + std::string generateDisassembly( Addr pc, const Loader::SymbolTable *symtab) const override; }; diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index f760b7813..0e3bbbde2 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -691,6 +691,32 @@ decode PO default Unknown::unknown() { } }}, true); + + 425: divde({{ + int64_t src1 = Ra_sd; + int64_t src2 = Rb_sd; + int64_t res; + std::tie(setOV, res, std::ignore) = divide(0, src1, src2); + if (!setOV) { + Rt = res; + } else { + Rt = 0; + } + }}, + true); + + 393: divdeu({{ + uint64_t src1 = Ra; + uint64_t src2 = Rb; + uint64_t res; + std::tie(setOV, res, std::ignore) = divide(0, src1, src2); + if (!setOV) { + Rt = res; + } else { + Rt = 0; + } + }}, + true); } default: decode XFX_XO { -- 2.30.2