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)
committerSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 06:38:17 +0000 (12:08 +0530)
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 293efdf56067c2706f5bed9371d20fd3ca0c9465..a1bf84249ecd29b79c3138a0696352143a3b311a 100644 (file)
@@ -112,6 +112,7 @@ IntArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 {
     stringstream ss;
     bool printSecondSrc = true;
+    bool printThirdSrc = false;
 
     // Generate the correct mnemonic
     string myMnemonic(mnemonic);
@@ -123,6 +124,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
@@ -146,6 +151,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 6a34184a28a5a4865216d8e83afea2c22c977c1e..c1391d863b0997ec4e8dda70c738545b508af186 100644 (file)
@@ -156,6 +156,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
@@ -196,6 +242,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 f7ae7ffb280ee1c83565d82e0b169c36bc794c6b..ce25be51725c2336613ed10ca19d1b513f0e82b1 100644 (file)
@@ -227,6 +227,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;