arch-power: Add doubleword multiply instructions
authorSandipan Das <sandipan@linux.ibm.com>
Sat, 6 Feb 2021 11:47:45 +0000 (17:17 +0530)
committerSandipan Das <sandipan@linux.ibm.com>
Mon, 15 Feb 2021 08:32:38 +0000 (14:02 +0530)
This introduces 128-bit multiplication helpers and adds
the following instructions.
  * Multiply Low Doubleword (mulld[o][.])
  * Multiply High Doubleword (mulhd[.])
  * Multiply High Doubleword Unsigned (mulhdu[.])

Change-Id: Id579c95468ffe5fe7b5164579ec1dfb18f0b3ab3
Signed-off-by: Sandipan Das <sandipan@linux.ibm.com>
src/arch/power/insts/integer.hh
src/arch/power/isa/decoder.isa

index a75f38b0cc1eb831fe18c0c1dd1cc7302ed558fc..12ad8fc99918f7c62a8b30bf1bef25fa5ea738b5 100644 (file)
@@ -154,6 +154,49 @@ class IntArithOp : public IntOp
     {
     }
 
+    /**
+     * Compute 128-bit product of 64-bit unsigned integer multiplication
+     * based on https://stackoverflow.com/a/28904636
+     */
+    inline std::tuple<uint64_t, uint64_t>
+    multiply(uint64_t ra, uint64_t rb) const
+    {
+        uint64_t plo, phi;
+    #if defined(__SIZEOF_INT128__)
+        __uint128_t prod = (__uint128_t)ra * rb;
+        plo = prod;
+        phi = prod >> 64;
+    #else
+        uint64_t ralo = (uint32_t)ra, rahi = ra >> 32;
+        uint64_t rblo = (uint32_t)rb, rbhi = rb >> 32;
+        uint64_t pp0 = ralo * rblo;
+        uint64_t pp1 = rahi * rblo;
+        uint64_t pp2 = ralo * rbhi;
+        uint64_t pp3 = rahi * rbhi;
+        uint64_t c = ((uint32_t)pp1) + ((uint32_t)pp2) + (pp0 >> 32);
+        phi = pp3 + (pp2 >> 32) + (pp1 >> 32) + (c >> 32);
+        plo = (c << 32) | ((uint32_t)pp0);
+    #endif
+        return std::make_tuple(plo, phi);
+    }
+
+    /* Compute 128-bit product of 64-bit signed integer multiplication */
+    inline std::tuple<uint64_t, int64_t>
+    multiply(int64_t ra, int64_t rb) const
+    {
+        uint64_t plo, phi;
+    #if defined(__SIZEOF_INT128__)
+        __int128_t prod = (__int128_t)ra * rb;
+        plo = prod;
+        phi = prod >> 64;
+    #else
+        std::tie(plo, phi) = multiply((uint64_t)ra, (uint64_t)rb);
+        if (rb < 0) phi -= (uint64_t)ra;
+        if (ra < 0) phi -= (uint64_t)rb;
+    #endif
+        return std::make_tuple(plo, (int64_t)phi);
+    }
+
     std::string generateDisassembly(
             Addr pc, const Loader::SymbolTable *symtab) const override;
 };
index ff4fecea9a96542b4b9de265b3a81df11483ae9c..13bbe87c700608f0bf7f8c0351835725bb4c040b 100644 (file)
@@ -557,6 +557,30 @@ decode PO default Unknown::unknown() {
                 }},
                 true);
 
+                73: mulhd({{
+                    int64_t res;
+                    std::tie(std::ignore, res) = multiply(Ra_sd, Rb_sd);
+                    Rt = res;
+                }});
+
+                9: mulhdu({{
+                    uint64_t res;
+                    std::tie(std::ignore, res) = multiply(Ra, Rb);
+                    Rt = res;
+                }});
+
+                233: mulld({{
+                    int64_t src1 = Ra_sd;
+                    int64_t src2 = Rb_sd;
+                    uint64_t res = src1 * src2;
+                    std::tie(res, std::ignore) = multiply(src1, src2);
+                    if (src1 != 0 && (int64_t)res / src1 != src2) {
+                        setOV = true;
+                    }
+                    Rt = res;
+                }},
+                true);
+
                 491: divw({{
                     int32_t src1 = Ra_sw;
                     int32_t src2 = Rb_sw;