arch-power: Add doubleword multiply-add instructions
[gem5.git] / src / arch / power / insts / integer.hh
index 12ad8fc99918f7c62a8b30bf1bef25fa5ea738b5..366d36adb134dceef9a3b531735992e45442f7eb 100644 (file)
@@ -154,6 +154,52 @@ class IntArithOp : public IntOp
     {
     }
 
+    /* Compute 128-bit sum of 128-bit to 64-bit unsigned integer addition */
+    inline std::tuple<uint64_t, uint64_t>
+    add(uint64_t ralo, uint64_t rahi, uint64_t rb) const
+    {
+        uint64_t slo, shi;
+    #if defined(__SIZEOF_INT128__)
+        __uint128_t ra = ((__uint128_t)rahi << 64) | ralo;
+        __uint128_t sum = ra + rb;
+        slo = sum;
+        shi = sum >> 64;
+    #else
+        shi = rahi + ((ralo + rb) < ralo);
+        slo = ralo + rb;
+    #endif
+        return std::make_tuple(slo, shi);
+    }
+
+    /* Compute 128-bit sum of 128-bit to 64-bit signed integer addition */
+    inline std::tuple<uint64_t, int64_t>
+    add(uint64_t ralo, int64_t rahi, int64_t rb) const
+    {
+        uint64_t slo;
+        int64_t shi;
+    #if defined(__SIZEOF_INT128__)
+        __int128_t ra = ((__int128_t)rahi << 64) | ralo;
+        __int128_t sum = (__int128_t)ra + rb;
+        slo = sum;
+        shi = sum >> 64;
+    #else
+        if (rb < 0) {
+            shi = rahi - 1;
+            slo = ralo + rb;
+            if (slo < rb) {
+                shi++;
+            }
+        } else {
+            shi = rahi;
+            slo = ralo + rb;
+            if (slo < rb) {
+                shi++;
+            }
+        }
+    #endif
+        return std::make_tuple(slo, shi);
+    }
+
     /**
      * Compute 128-bit product of 64-bit unsigned integer multiplication
      * based on https://stackoverflow.com/a/28904636
@@ -197,6 +243,48 @@ class IntArithOp : public IntOp
         return std::make_tuple(plo, (int64_t)phi);
     }
 
+    /**
+     * Compute 128-bit result of 64-bit unsigned integer multiplication
+     * followed by addition
+     */
+    inline std::tuple<uint64_t, uint64_t>
+    multiplyAdd(uint64_t ra, uint64_t rb, uint64_t rc) const
+    {
+        uint64_t rlo, rhi;
+    #if defined(__SIZEOF_INT128__)
+        __uint128_t res = ((__uint128_t)ra * rb) + rc;
+        rlo = res;
+        rhi = res >> 64;
+    #else
+        uint64_t plo, phi;
+        std::tie(plo, phi) = multiply(ra, rb);
+        std::tie(rlo, rhi) = add(plo, phi, rc);
+    #endif
+        return std::make_tuple(rlo, rhi);
+    }
+
+    /**
+     * Compute 128-bit result of 64-bit signed integer multiplication
+     * followed by addition
+     */
+    inline std::tuple<uint64_t, int64_t>
+    multiplyAdd(int64_t ra, int64_t rb, int64_t rc) const
+    {
+        uint64_t rlo;
+        int64_t rhi;
+    #if defined(__SIZEOF_INT128__)
+        __int128_t res = (__int128_t)ra * rb + rc;
+        rlo = res;
+        rhi = res >> 64;
+    #else
+        uint64_t plo;
+        int64_t phi;
+        std::tie(plo, phi) = multiply(ra, rb);
+        std::tie(rlo, rhi) = add(plo, phi, rc);
+    #endif
+        return std::make_tuple(rlo, rhi);
+    }
+
     std::string generateDisassembly(
             Addr pc, const Loader::SymbolTable *symtab) const override;
 };