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 <sandipan@linux.ibm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/40908
Reviewed-by: Boris Shingarov <shingarov@labware.com>
Maintainer: Boris Shingarov <shingarov@labware.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Sandipan Das
2021-02-06 17:18:05 +05:30
parent d9233aa168
commit 3d2bb88f62
2 changed files with 118 additions and 0 deletions

View File

@@ -265,6 +265,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<bool, uint64_t, uint64_t>
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<bool, int64_t, int64_t>
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;
};

View File

@@ -574,6 +574,18 @@ decode PO default Unknown::unknown() {
266: IntSumOp::add({{ Ra }}, {{ Rb }});
format IntArithCheckRcOp {
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);
395: divweu({{
uint32_t src1 = Ra_ud;
uint32_t src2 = Rb_ud;
@@ -592,6 +604,18 @@ 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);
427: divwe({{
int32_t src1 = Ra_sw;
int32_t src2 = Rb_sw;