arch-power: Add doubleword divide-extended instructions
authorSandipan Das <sandipan@linux.ibm.com>
Sat, 6 Feb 2021 11:48:05 +0000 (17:18 +0530)
committerSandipan Das <sandipan@linux.ibm.com>
Mon, 15 Feb 2021 08:32:38 +0000 (14:02 +0530)
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>
src/arch/power/insts/integer.hh
src/arch/power/isa/decoder.isa

index 366d36adb134dceef9a3b531735992e45442f7eb..38c0dd0d39f617723d0438a6bfca5beaa76e77cc 100644 (file)
@@ -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<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;
 };
index f760b7813e8c0b3e88c600f275f0bb8c84cdaeb0..0e3bbbde247976211bea34dae5bce86d72afd575 100644 (file)
@@ -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 {