* ppc-dis.c (PPC_OPC_SEGS, PPC_OP_TO_SEG): Delete.
authorAlan Modra <amodra@gmail.com>
Fri, 16 Mar 2012 12:14:32 +0000 (12:14 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 16 Mar 2012 12:14:32 +0000 (12:14 +0000)
(powerpc_opcd_indices): Bump array size.
(disassemble_init_powerpc): Set powerpc_opcd_indices entries
corresponding to unused opcodes to following entry.
(lookup_powerpc): New function, extracted and optimised from..
(print_insn_powerpc): ..here.

opcodes/ChangeLog
opcodes/ppc-dis.c

index 3595faf5285bbe4e92b51885973cb0504c31361f..37f636455134ef6291e503c114e97d3af83339aa 100644 (file)
@@ -1,3 +1,12 @@
+2012-03-16  Alan Modra  <amodra@gmail.com>
+
+       * ppc-dis.c (PPC_OPC_SEGS, PPC_OP_TO_SEG): Delete.
+       (powerpc_opcd_indices): Bump array size.
+       (disassemble_init_powerpc): Set powerpc_opcd_indices entries
+       corresponding to unused opcodes to following entry.
+       (lookup_powerpc): New function, extracted and optimised from..
+       (print_insn_powerpc): ..here.
+
 2012-03-15  Alan Modra  <amodra@gmail.com>
            James Lemke  <jwlemke@codesourcery.com>
 
index d2cd2e59166fd6f36e222b5d886e3f5422ad3eca..da72fcf1d733cf61253010b86e71d0d2c5d80d24 100644 (file)
@@ -265,9 +265,7 @@ powerpc_init_dialect (struct disassemble_info *info)
   POWERPC_DIALECT(info) = dialect;
 }
 
-#define PPC_OPCD_SEGS 64
-#define PPC_OP_TO_SEG(i) (i)
-static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS];
+static unsigned short powerpc_opcd_indices[65];
 
 /* Calculate opcode table indices to speed up disassembly,
    and init dialect.  */
@@ -276,17 +274,22 @@ void
 disassemble_init_powerpc (struct disassemble_info *info)
 {
   int i;
-
-  for (i = 0; i < PPC_OPCD_SEGS; ++i)
-    powerpc_opcd_indices[i] = powerpc_num_opcodes;
+  unsigned short last;
 
   i = powerpc_num_opcodes;
   while (--i >= 0)
     {
       unsigned op = PPC_OP (powerpc_opcodes[i].opcode);
-      unsigned seg = PPC_OP_TO_SEG (op);
 
-      powerpc_opcd_indices[seg] = i;
+      powerpc_opcd_indices[op] = i;
+    }
+
+  last = powerpc_num_opcodes;
+  for (i = 64; i > 0; --i)
+    {
+      if (powerpc_opcd_indices[i] == 0)
+       powerpc_opcd_indices[i] = last;
+      last = powerpc_opcd_indices[i];
     }
 
   if (info->arch == bfd_arch_powerpc)
@@ -367,6 +370,52 @@ skip_optional_operands (const unsigned char *opindex,
   return 1;
 }
 
+/* Find a match for INSN in the opcode table, given machine DIALECT.
+   A DIALECT of -1 is special, matching all machine opcode variations.  */
+   
+static const struct powerpc_opcode *
+lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
+{
+  const struct powerpc_opcode *opcode;
+  const struct powerpc_opcode *opcode_end;
+  unsigned long op;
+
+  /* Get the major opcode of the instruction.  */
+  op = PPC_OP (insn);
+
+  /* Find the first match in the opcode table for this major opcode.  */
+  opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1];
+  for (opcode = powerpc_opcodes + powerpc_opcd_indices[op];
+       opcode < opcode_end;
+       ++opcode)
+    {
+      const unsigned char *opindex;
+      const struct powerpc_operand *operand;
+      int invalid;
+
+      if ((insn & opcode->mask) != opcode->opcode
+         || (dialect != (ppc_cpu_t) -1
+             && ((opcode->flags & dialect) == 0
+                 || (opcode->deprecated & dialect) != 0)))
+       continue;
+
+      /* Check validity of operands.  */
+      invalid = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+       {
+         operand = powerpc_operands + *opindex;
+         if (operand->extract)
+           (*operand->extract) (insn, dialect, &invalid);
+       }
+      if (invalid)
+       continue;
+
+      return opcode;
+    }
+
+  return NULL;
+}
+
 /* Print a PowerPC or POWER instruction.  */
 
 static int
@@ -379,8 +428,6 @@ print_insn_powerpc (bfd_vma memaddr,
   int status;
   unsigned long insn;
   const struct powerpc_opcode *opcode;
-  const struct powerpc_opcode *opcode_end;
-  unsigned long op;
 
   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
   if (status != 0)
@@ -394,52 +441,18 @@ print_insn_powerpc (bfd_vma memaddr,
   else
     insn = bfd_getl32 (buffer);
 
-  /* Get the major opcode of the instruction.  */
-  op = PPC_OP (insn);
+  opcode = lookup_powerpc (insn, dialect);
+  if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
+    opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
 
-  /* Find the first match in the opcode table.
-     We speed this up by segmenting the opcode table and starting the search
-     at one of the segment boundaries.  */
-  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
- again:
-  for (opcode = powerpc_opcodes + powerpc_opcd_indices[PPC_OP_TO_SEG (op)];
-       opcode < opcode_end;
-       ++opcode)
+  if (opcode != NULL)
     {
-      unsigned long table_op;
       const unsigned char *opindex;
       const struct powerpc_operand *operand;
-      int invalid;
       int need_comma;
       int need_paren;
       int skip_optional;
 
-      table_op = PPC_OP (opcode->opcode);
-      if (op > table_op)
-       continue;
-      if (op < table_op)
-       break;
-
-      if ((insn & opcode->mask) != opcode->opcode
-         || (opcode->flags & dialect) == 0
-         || (dialect != ~(ppc_cpu_t) PPC_OPCODE_ANY
-             && (opcode->deprecated & dialect) != 0))
-       continue;
-
-      /* Make two passes over the operands.  First see if any of them
-        have extraction functions, and, if they do, make sure the
-        instruction is valid.  */
-      invalid = 0;
-      for (opindex = opcode->operands; *opindex != 0; opindex++)
-       {
-         operand = powerpc_operands + *opindex;
-         if (operand->extract)
-           (*operand->extract) (insn, dialect, &invalid);
-       }
-      if (invalid)
-       continue;
-
-      /* The instruction is valid.  */
       if (opcode->operands[0] != 0)
        (*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
       else
@@ -540,12 +553,6 @@ print_insn_powerpc (bfd_vma memaddr,
       return 4;
     }
 
-  if ((dialect & PPC_OPCODE_ANY) != 0)
-    {
-      dialect = ~(ppc_cpu_t) PPC_OPCODE_ANY;
-      goto again;
-    }
-
   /* We could not find a match.  */
   (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);