arch-power: Add fixed-point doubleword multipy-add instructions
authorSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 06:30:28 +0000 (12:00 +0530)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 24 Jan 2021 03:21:20 +0000 (03:21 +0000)
This adds the following arithmetic instructions:
  * Multiply-Add Low Doubleword (maddld)
  * Multiply-Add High Doubleword (maddhd)
  * Multiply-Add High Doubleword Unsigned (maddhdu)

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

index 638634972776dcdc286d3e623244702e62ad995e..e5692bb2285b479da58895ee65190097793a2463 100644 (file)
@@ -110,6 +110,7 @@ IntArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 {
     stringstream ss;
     bool printSecondSrc = true;
+    bool printThirdSrc = false;
 
     // Generate the correct mnemonic
     string myMnemonic(mnemonic);
@@ -121,6 +122,10 @@ IntArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
         !myMnemonic.compare("subfze") ||
         !myMnemonic.compare("neg")){
         printSecondSrc = false;
+    } else if (!myMnemonic.compare("maddhd") ||
+               !myMnemonic.compare("maddhdu") ||
+               !myMnemonic.compare("maddld")) {
+        printThirdSrc = true;
     }
 
     // Additional characters depending on isa bits being set
@@ -144,6 +149,12 @@ IntArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
         if (_numSrcRegs > 1 && printSecondSrc) {
             ss << ", ";
             printReg(ss, _srcRegIdx[1]);
+
+            // Print the third source register
+            if (_numSrcRegs > 2 && printThirdSrc) {
+                ss << ", ";
+                printReg(ss, _srcRegIdx[2]);
+            }
         }
     }
 
index 63e9501e861808020a6c382b1cef4e41f3c5a790..53875021590afd9a7628abbe2ff69a07494f816b 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 */
     inline std::tuple<uint64_t, uint64_t>
     multiply(uint64_t ra, uint64_t rb) const
@@ -194,6 +240,44 @@ 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 SymbolTable *symtab) const override;
 };
index baabc41f64e3d023e8a257460d5d2b6c6e485025..83e3efca2af7b5c6462d287dc0b2e0dc8cb6f6af 100644 (file)
@@ -225,6 +225,31 @@ decode PO default Unknown::unknown() {
         }});
     }
 
+    4: decode VA_XO {
+
+        // Arithmetic instructions that use source registers Ra, Rb and Rc,
+        // with destination register Rt.
+        format IntArithOp {
+            48: maddhd({{
+                int64_t res;
+                std::tie(std::ignore, res) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd);
+                Rt = res;
+            }});
+
+            49: maddhdu({{
+                uint64_t res;
+                std::tie(std::ignore, res) = multiplyAdd(Ra, Rb, Rc);
+                Rt = res;
+            }});
+
+            51: maddld({{
+                uint64_t res;
+                std::tie(res, std::ignore) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd);
+                Rt = res;
+            }});
+        }
+    }
+
     format IntImmOp {
         10: cmpli({{
             Xer xer = XER;