import dataclasses
 import enum
 import itertools
+import operator
 import pathlib
-import sys
 
 import mdis.dispatcher
 import mdis.visitor
     yield f"UINT64_C(0)"
 
 
+def store(span):
+    bits = len(span)
+    one = "UINT64_C(1)"
+    for (dst, origin) in enumerate(span):
+        src = (32 - (origin + 1))
+        dst = (bits - (dst + 1))
+        dst = f"UINT64_C({dst})"
+        src = f"UINT64_C({src})"
+        yield f"/* {origin:<2} */ (((operand->value >> {dst}) & {one}) << {src}) |"
+    yield f"UINT64_C(0)"
+
+
+def unwrap(integer):
+    for bit in range(31, -1, -1):
+        yield ((integer >> bit) & 1)
+
+
+def wrap(bits):
+    value = 0
+    for (index, bit) in enumerate(reversed(bits)):
+        if bit:
+            value |= (1 << index)
+    return value
+
+
 class Mode(enum.Enum):
-    PPC_DIS_GEN_C = "opid-dis-gen.c"
-    PPC_OPC_GEN_C = "opid-opc-gen.c"
+    DIS_GEN_C = "opid-dis-gen.c"
+    OPC_GEN_C = "opid-opc-gen.c"
 
     def __call__(self, db, **arguments):
         def pairwise(iterable):
 
         cache = Cache()
         codegen = {
-            Mode.PPC_DIS_GEN_C: DisGenSource,
-            Mode.PPC_OPC_GEN_C: OpcGenSource,
+            Mode.DIS_GEN_C: DisGenSource,
+            Mode.OPC_GEN_C: OpcGenSource,
         }[self](cache=cache, **arguments)
         for (root, visitor) in pairwise((db, cache, codegen),):
             walker_cls = getattr(visitor, "Walker", Walker)
 class DynamicOperandIds(tuple): pass
 class StaticOperands(tuple): pass
 class DynamicOperands(tuple): pass
-class POTable(tuple): pass
+class OpcodeIds(tuple): pass
+class NameTable(tuple): pass
+class OpcodeTable(tuple): pass
 class RecordTable(tuple): pass
 
 
+class Opcode(insndb.Opcode):
+    @property
+    def PO(self):
+        (*_, result) = itertools.accumulate((
+            (((self.value >> 31) & 1) << 5), # 0
+            (((self.value >> 30) & 1) << 4), # 1
+            (((self.value >> 29) & 1) << 3), # 2
+            (((self.value >> 28) & 1) << 2), # 3
+            (((self.value >> 27) & 1) << 1), # 4
+            (((self.value >> 26) & 1) << 0), # 5
+        ), operator.or_)
+        return result
+
+    @property
+    def weight(self):
+        bits = tuple(unwrap(self.mask)).count(1)
+        return (self.PO, -bits, self.mask)
+
+    def __lt__(self, other):
+        if not isinstance(other, self.__class__):
+            return NotImplemented
+        return self.weight < other.weight
+
 class DynamicOperandId(Struct):
     name: str = "NIL"
     index: int = 0
 
 
+class NameId(Struct):
+    name: str
+    index: int
+
+
 class DynamicOperand(Struct):
     cls: type
     span: tuple
 
 class Record(Struct):
     name: str
-    opcode: insndb.Record.Opcode
+    opcode: Opcode
     dynamic_operand_ids: DynamicOperandIds
     static_operands: StaticOperands
 
 class Cache(mdis.visitor.ContextVisitor):
     def __init__(self):
         self.__PO = ([0] * (1 << 6))
-        self.__records = collections.defaultdict(list)
+        self.__records = []
         self.__static_operand = collections.defaultdict(list)
         self.__dynamic_operand = collections.defaultdict(set)
         self.__dynamic_operand_id = collections.defaultdict(list)
         return super().__init__()
 
     def __iter__(self):
-        table = tuple(self.__dynamic_operand.keys())
+        name_table = {}
+        operands_table = tuple(self.__dynamic_operand.keys())
         nil = DynamicOperandId()
 
         def dynamic_operand_id(item):
             (name, cls, span) = item
-            index = (table.index((cls, span),) + 1)
+            index = (operands_table.index((cls, span),) + 1)
             return DynamicOperandId(name=name, index=index)
 
         def dynamic_operand(item):
             ((cls, span), names) = item
             return DynamicOperand(cls=cls, span=span, names=tuple(sorted(names)))
 
+        def name_id(item):
+            (name, index) = item
+            return NameId(name=name, index=index)
+
         def record(item):
-            (opcode, name) = item
+            (index, (opcode, name)) = item
+            name_table[name] = index
             dynamic_operand_ids = map(dynamic_operand_id, self.__dynamic_operand_id[name])
             dynamic_operand_ids = DynamicOperandIds(tuple(dynamic_operand_ids) + (nil,))
-            static_operands = StaticOperands(self.__static_operand[name])
+            static_operands = StaticOperands(dict.fromkeys(self.__static_operand[name]))
 
             return Record(opcode=opcode, name=name,
                 dynamic_operand_ids=dynamic_operand_ids,
                 static_operands=static_operands)
 
         yield DynamicOperands(map(dynamic_operand, self.__dynamic_operand.items()))
-        yield RecordTable(map(record, sorted(self.__records.items())))
-        yield POTable(self.__PO)
+        yield RecordTable(map(record, enumerate(sorted(self.__records))))
+        yield OpcodeTable(self.__PO)
+        yield NameTable(sorted(map(name_id, name_table.items()), key=lambda item: item.name))
 
     @mdis.dispatcher.Hook(insndb.Record)
     @contextlib.contextmanager
     @mdis.dispatcher.Hook(insndb.Record.Opcode)
     @contextlib.contextmanager
     def dispatch_record_opcode(self, node):
-        self.__records[node] = self.__record.name
         self.__PO[self.__record.PO] += 1
         yield node
 
+    @mdis.dispatcher.Hook(insndb.Record.Opcodes)
+    @contextlib.contextmanager
+    def dispatch_record_opcodes(self, node):
+        masks = {subnode.mask for subnode in node}
+        if len(masks) != 1:
+            raise ValueError(masks)
+        mask = list(unwrap(masks.pop()))
+        states = tuple(unwrap(node[0].value))
+        for subnode in node[1:]:
+            for (index, bit) in enumerate(unwrap(subnode.value)):
+                if mask[index] and (states[index] != bit):
+                    mask[index] = 0
+
+        mask = insndb.Record.Opcode.Mask(wrap(mask))
+        opcode = Opcode(node[0].value, mask)
+        self.__records.append((opcode, self.__record.name))
+
+        yield node
+
     @mdis.dispatcher.Hook(insndb.StaticOperand)
     @contextlib.contextmanager
     def dispatch_static_operand(self, node):
 
 
 class Source(Codegen):
+    class Walker(Walker):
+        @mdis.dispatcher.Hook(DynamicOperand, RecordTable)
+        def dispatch_ignore(self, node):
+            yield from ()
+
+        @mdis.dispatcher.Hook(Cache)
+        def dispatch_cache(self, node):
+            (operands, _, _, _) = node
+            yield from self([operands])
+
     @mdis.dispatcher.Hook(str)
     @contextlib.contextmanager
     def dispatch_str(self, node, *, path, pathcls):
 
         @mdis.dispatcher.Hook(Cache)
         def dispatch_cache(self, node):
-            (operands, _, _) = node
+            (operands, _, _, _) = node
             yield from self([operands])
 
     @mdis.dispatcher.Hook(DynamicOperands)
             yield node
             self.emit("default:")
             with self:
-                self.emit("return OPID_ERROR_OPERAND_0;")
+                self.emit("return OPID_ERROR_OPERAND_0_LOOKUP;")
             self.emit("}")
         self.emit("")
         with self:
 
 class OpcGenSource(Source):
     class Walker(Walker):
-        @mdis.dispatcher.Hook(DynamicOperandId, DynamicOperands, insndb.StaticOperand, POTable)
+        @mdis.dispatcher.Hook(DynamicOperandId, NameId, Opcode,
+            DynamicOperands, insndb.StaticOperand, OpcodeTable)
         def dispatch_ignore(self, node):
             yield from ()
 
 
         @mdis.dispatcher.Hook(Cache)
         def dispatch_cache(self, node):
-            (_, records, potable) = node
-            yield from self([records, potable])
+            (_, records, opcodes, names) = node
+            yield from self([records, opcodes, names])
 
     @mdis.dispatcher.Hook(DynamicOperandId)
     @contextlib.contextmanager
         self.emit(f"{pathcls(path)} = UINT64_C(0x{node:016x}),")
         with self: yield node
 
-    @mdis.dispatcher.Hook(insndb.Record.Opcode)
+    @mdis.dispatcher.Hook(Opcode)
     @contextlib.contextmanager
     def dispatch_opcode(self, node):
         self.emit(".opcode = {")
-        with self: yield node
+        with self:
+            self.emit(f".value = UINT64_C(0x{node.value:08x}),")
+            self.emit(f".mask = UINT64_C(0x{node.mask:08x}),")
         self.emit("},")
+        yield node
 
-    @mdis.dispatcher.Hook(POTable)
+    @mdis.dispatcher.Hook(OpcodeTable)
     @contextlib.contextmanager
     def dispatch_potable(self, node):
         heads = ([0] * (1 << 6))
             for index in range(64):
                 head = heads[index]
                 tail = tails[index]
-                self.emit(f"[0x{index:02x}] = {{{head}, {tail}}},")
+                self.emit(f"[{index}] = {{{head}, {tail}}},")
         self.emit("};")
+        self.emit("")
+        yield node
+
+    @mdis.dispatcher.Hook(NameId)
+    @contextlib.contextmanager
+    def dispatch_name_id(self, node):
+        self.emit(f"{{\"{node.name}\", &opid_record_table[{node.index}]}},")
         yield node
 
+    @mdis.dispatcher.Hook(NameTable)
+    @contextlib.contextmanager
+    def dispatch_name_table(self, node):
+        self.emit(f"static struct opid_name_id const opid_name_id_table[] = {{")
+        with self:
+            yield node
+        self.emit("};")
+
     @mdis.dispatcher.Hook(RecordTable)
     @contextlib.contextmanager
     def dispatch_records(self, node):