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)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 24 Jan 2021 03:27:13 +0000 (03:27 +0000)
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 af61fa700e9d63c28e6bac58fcedfb543077871f..b5edc4e48c20eae1c6cd3360bfeb6ce2603ab601 100644 (file)
@@ -705,8 +705,40 @@ IntRotateOp::generateDisassembly(
         Addr pc, const Loader::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) {
@@ -719,10 +751,40 @@ IntRotateOp::generateDisassembly(
             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 5e5b7eb235d6df1b60ffb109527358172d0826ef..a2eaaa52bc44baa74830d39163e9689f993d94db 100644 (file)
@@ -631,34 +631,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 1603e86caf5a0f1e372690d3fe388b9f239930ad..432dd118c8cb9a2e9bb8c506380d6a294df24a2f 100644 (file)
@@ -282,10 +282,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 3524606955a370e571116eec0dbddbde9713e0d2..d8c09d5d21be1f665bfb167db4d383cdad83ff19 100644 (file)
@@ -521,15 +521,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