arch-power: Add doubleword multiply-add instructions
authorSandipan Das <sandipan@linux.ibm.com>
Sat, 6 Feb 2021 11:47:53 +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 addition helpers and adds the
following instructions.
  * Multiply-Add Low Doubleword (maddld)
  * Multiply-Add High Doubleword (maddhd)
  * Multiply-Add High Doubleword Unsigned (maddhdu)

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

index d2862ff39126ae533b767d8a36637ae799a03a52..da7f392eac925fc1cf677377d9fbc5abe14db1b3 100644 (file)
@@ -119,6 +119,7 @@ IntArithOp::generateDisassembly(
 {
     std::stringstream ss;
     bool printSecondSrc = true;
+    bool printThirdSrc = false;
 
     // Generate the correct mnemonic
     std::string myMnemonic(mnemonic);
@@ -130,6 +131,10 @@ IntArithOp::generateDisassembly(
         !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
@@ -153,6 +158,12 @@ IntArithOp::generateDisassembly(
         if (_numSrcRegs > 1 && printSecondSrc) {
             ss << ", ";
             printReg(ss, srcRegIdx(1));
+
+            // Print the third source register
+            if (_numSrcRegs > 2 && printThirdSrc) {
+                ss << ", ";
+                printReg(ss, srcRegIdx(2));
+            }
         }
     }
 
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;
 };
index 13bbe87c700608f0bf7f8c0351835725bb4c040b..4297d7d143d1741ba645acc1ceab90d36a326306 100644 (file)
@@ -209,6 +209,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;
index cb858a8e356bcc9c5654102b1ba58bc966e69fe5..6860c26a703f6d4c916bc468e6e779862eac3a27 100644 (file)
@@ -328,6 +328,16 @@ def format IntSumOp(src1, src2, ca = {{ 0 }}, computeCA = 0,
 
 }};
 
+// Instructions that use source registers Ra and Rb, with the result
+// placed into Rt but do not check for carry, overflow or the Rc bit.
+def format IntArithOp(code, inst_flags = []) {{
+
+    # Generate the class
+    (header_output, decoder_output, decode_block, exec_output) = \
+        GenAluOp(name, Name, 'IntArithOp', code, inst_flags, BasicDecode,
+                 BasicConstructor)
+}};
+
 
 // Instructions that use source registers Ra and Rb, with the result
 // placed into Rt. Basically multiply and divide instructions. The