power_insn: support PPC multi-records
authorDmitry Selyutin <ghostmansd@gmail.com>
Sat, 3 Sep 2022 20:15:54 +0000 (23:15 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Sat, 3 Sep 2022 20:15:54 +0000 (23:15 +0300)
src/openpower/decoder/power_insn.py

index a655111ef7cd0b9ce240fbedf2fdd85a04ba2131..d4baa44715b4902e8369567dd056cf14971ae4a5 100644 (file)
@@ -234,6 +234,38 @@ class PPCRecord:
         return frozenset(self.comment.split("=")[-1].split("/"))
 
 
+class PPCMultiRecord(tuple):
+    @cached_property
+    def unified(self):
+        def merge(lhs, rhs):
+            value = 0
+            mask = 0
+            lvalue = lhs.opcode.value
+            rvalue = rhs.opcode.value
+            lmask = lhs.opcode.mask
+            rmask = rhs.opcode.mask
+            bits = max(lmask.bit_length(), rmask.bit_length())
+            for bit in range(bits):
+                lvstate = ((lvalue & (1 << bit)) != 0)
+                rvstate = ((rvalue & (1 << bit)) != 0)
+                lmstate = ((lmask & (1 << bit)) != 0)
+                rmstate = ((rmask & (1 << bit)) != 0)
+                vstate = lvstate
+                mstate = True
+                if (not lmstate or not rmstate) or (lvstate != rvstate):
+                    vstate = 0
+                    mstate = 0
+                value |= (vstate << bit)
+                mask |= (mstate << bit)
+
+            return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
+
+        return _functools.reduce(merge, self)
+
+    def __getattr__(self, attr):
+        return getattr(self.unified, attr)
+
+
 @_dataclasses.dataclass(eq=True, frozen=True)
 class SVP64Record:
     class ExtraMap(tuple):
@@ -1186,38 +1218,10 @@ class PPCDatabase:
                     for insn in parse(stream, factory):
                         records[section][insn.comment].add(insn)
 
-        # Once we collected all instructions with the same identifier,
-        # it's time to merge the different opcodes into the single pattern.
-        # At this point, we only consider masks; the algorithm as follows:
-        # 1. If any of two masks ignores the bit, it's ignored entirely.
-        # 2. If the bit is not equal between masks, it's ignored.
-        # 3. Otherwise the bits are equal and considered.
-        def merge(lhs, rhs):
-            value = 0
-            mask = 0
-            lvalue = lhs.opcode.value
-            rvalue = rhs.opcode.value
-            lmask = lhs.opcode.mask
-            rmask = rhs.opcode.mask
-            bits = max(lmask.bit_length(), rmask.bit_length())
-            for bit in range(bits):
-                lvstate = ((lvalue & (1 << bit)) != 0)
-                rvstate = ((rvalue & (1 << bit)) != 0)
-                lmstate = ((lmask & (1 << bit)) != 0)
-                rmstate = ((rmask & (1 << bit)) != 0)
-                vstate = lvstate
-                mstate = True
-                if (not lmstate or not rmstate) or (lvstate != rvstate):
-                    vstate = 0
-                    mstate = 0
-                value |= (vstate << bit)
-                mask |= (mstate << bit)
-            return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
-
         db = dd(set)
         for (section, group) in records.items():
             for records in group.values():
-                db[section].add(_functools.reduce(merge, records))
+                db[section].add(PPCMultiRecord(records))
 
         self.__db = db
         self.__mdwndb = mdwndb