arch-power: Fix fixed-point word rotate instructions
authorSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 13:16:02 +0000 (18:46 +0530)
committerSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 13:16:58 +0000 (18:46 +0530)
This fixes the following rotate instructions:
  * Rotate Left Word Immediate then And with Mask (rlwinm[.])
  * Rotate Left Word then And with Mask (rlwnm[.])
  * Rotate Left Word Immediate then Mask Insert (rlwimi[.])

For 64-bit execution, these instructions should perform rotate
operations on a 64-bit value formed by concatenating two copies
of the lower order 32 bits of the value in the source register.

This also fixes disassembly generation for all of the above.

Change-Id: Iccd8c6ad10a26d66dcecd64c8f1f8118ec8c1278
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
src/arch/power/isa/formats/integer.isa

index 090ec480274910139618e1fe4df76b6e8bbedb72..ce4ab463d951da36ce3150fde62568ed703df2b5 100644 (file)
@@ -697,8 +697,40 @@ string
 IntRotateOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 {
     stringstream ss;
+    bool printSecondSrc = true;
+    bool printShift = true;
+    bool printMaskBeg = true;
+    bool printMaskEnd = true;
 
-    ccprintf(ss, "%-10s ", mnemonic);
+    // Generate the correct mnemonic
+    string myMnemonic(mnemonic);
+
+    // Special cases
+    if (!myMnemonic.compare("rlwinm")) {
+        if (maskBeg == 0 && maskEnd == 31) {
+            myMnemonic = "rotlwi";
+            printMaskBeg = false;
+            printMaskEnd = false;
+        } else if (shift == 0 && maskEnd == 31) {
+            myMnemonic = "clrlwi";
+            printShift = false;
+            printMaskEnd = false;
+        }
+        printSecondSrc = false;
+    } else if (!myMnemonic.compare("rlwnm")) {
+        if (maskBeg == 0 && maskEnd == 31) {
+            myMnemonic = "rotlw";
+            printMaskBeg = false;
+            printMaskEnd = false;
+        }
+        printShift = false;
+    } else if (!myMnemonic.compare("rlwimi")) {
+        printSecondSrc = false;
+    }
+
+    // Additional characters depending on isa bits being set
+    if (rcSet) myMnemonic = myMnemonic + ".";
+    ccprintf(ss, "%-10s ", myMnemonic);
 
     // Print the first destination only
     if (_numDestRegs > 0) {
@@ -711,10 +743,40 @@ IntRotateOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
             ss << ", ";
         }
         printReg(ss, _srcRegIdx[0]);
+
+        // Print the second source register
+        if (printSecondSrc) {
+
+            // If the instruction updates the CR, the destination register
+            // Ra is read and thus, it becomes the second source register
+            // due to its higher precedence over Rb. In this case, it must
+            // be skipped.
+            if (rcSet) {
+                if (_numSrcRegs > 2) {
+                    ss << ", ";
+                    printReg(ss, _srcRegIdx[2]);
+                }
+            } else {
+                if (_numSrcRegs > 1) {
+                    ss << ", ";
+                    printReg(ss, _srcRegIdx[1]);
+                }
+            }
+        }
+    }
+
+    // Print the shift value
+    if (printShift) {
+        ss << ", " << shift;
     }
 
-    // Print the shift, mask begin and mask end
-    ss << ", " << sh << ", " << mb << ", " << me;
+    // Print the mask bounds
+    if (printMaskBeg) {
+        ss << ", " << maskBeg;
+    }
+    if (printMaskEnd) {
+        ss << ", " << maskEnd;
+    }
 
     return ss.str();
 }
index 15a2b9fc3540759cf2ce036f1f1ba24e4539eaba..95d64b3383240f7c6f9d15b5d40c69ef7024856a 100644 (file)
@@ -633,34 +633,46 @@ class IntConcatShiftOp : public IntOp
 
 
 /**
- * Class for integer rotate operations.
+ * Class for integer rotate operations with a shift amount obtained
+ * from a register or an immediate and the first and last bits of a
+ * mask obtained from immediates.
  */
 class IntRotateOp : public IntShiftOp
 {
   protected:
 
-    uint32_t mb;
-    uint32_t me;
-    uint32_t fullMask;
+    uint32_t maskBeg;
+    uint32_t maskEnd;
 
     /// Constructor
     IntRotateOp(const char *mnem, MachInst _machInst, OpClass __opClass)
       : IntShiftOp(mnem, _machInst, __opClass),
-        mb(machInst.mb),
-        me(machInst.me)
+        maskBeg(machInst.mb),
+        maskEnd(machInst.me)
     {
-        if (me >= mb) {
-            fullMask = mask(31 - mb, 31 - me);
-        } else {
-            fullMask = ~mask(31 - (me + 1), 31 - (mb - 1));
-        }
     }
 
-    uint32_t
-    rotateValue(uint32_t rs, uint32_t shift) const
+    inline uint64_t
+    rotate(uint32_t rs, uint32_t sh) const
     {
-        uint32_t n = shift & 31;
-        return (rs << n) | (rs >> (32 - n));
+        uint64_t res;
+        sh = sh & 0x1f;
+        res = rs;
+        res = (res << 32) | res;
+        res = (res << sh) | (res >> (32 - sh));
+        return res;
+    }
+
+    inline uint64_t
+    bitmask(uint32_t mb, uint32_t me) const
+    {
+        mb = mb & 0x1f;
+        me = me & 0x1f;
+        if (mb <= me) {
+            return mask(31 - mb, 31 - me);
+        } else {
+            return ~mask(31 - (me + 1), 31 - (mb - 1));
+        }
     }
 
     std::string generateDisassembly(
index af710edbcbb331257fd21c22fc4fd5a52d5754e2..5933bca480a920b9c1d9872d00490e34c53fbd14 100644 (file)
@@ -284,10 +284,27 @@ decode PO default Unknown::unknown() {
     }
 
     format IntRotateOp {
-        21: rlwinm({{ Ra = rotateValue(Rs, sh) & fullMask; }});
-        23: rlwnm({{ Ra = rotateValue(Rs, Rb) & fullMask; }});
-        20: rlwimi({{ Ra = (rotateValue(Rs, sh) & fullMask) |
-                           (Ra & ~fullMask); }});
+        21: rlwinm({{
+            uint64_t res;
+            res = rotate(Rs, shift);
+            res = res & bitmask(maskBeg, maskEnd);
+            Ra = res;
+        }});
+
+        23: rlwnm({{
+            uint64_t res;
+            res = rotate(Rs, Rb);
+            res = res & bitmask(maskBeg, maskEnd);
+            Ra = res;
+        }});
+
+        20: rlwimi({{
+            uint64_t res, mask;
+            mask = bitmask(maskBeg, maskEnd);
+            res = rotate(Rs, shift);
+            res = (res & mask) | (Ra & ~mask);
+            Ra = res;
+        }});
     }
 
     // There are a large number of instructions that have the same primary
index 8f8c2bd41ccf5cf4883c3889a0f55400f54d9026..78f8062db670c8597a610e944e4ba0ab737655ce 100644 (file)
@@ -523,15 +523,17 @@ def format IntConcatShiftOp(code, computeCA = 0, inst_flags = []) {{
 }};
 
 
-// A special format for rotate instructions which use certain fields
-// from the instruction's binary encoding. We need two versions for each
-// instruction to deal with the Rc bit.
+// Integer instructions with or without immediate that perform rotate
+// operations. All instructions write to Ra and use Rs as a source
+// register. If immediate is not used, Rb is also used as a source
+// register. We need two versions for each instruction to deal with
+// the Rc bit.
 def format IntRotateOp(code, inst_flags = []) {{
 
     # The result is always in Ra
     dict = {'result':'Ra'}
 
-    # Setup the code for when Rc is set
+    # Code when Rc is set
     code_rc1 = readXERCode + code + computeCR0Code % dict
 
     # Generate the first class