This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: RFA: performance improvement for PowerPC disassembly
On Thu, Mar 15, 2012 at 10:32:36PM +1030, Alan Modra wrote:
> The middle of print_insn_powerpc should then look like
[snip]
As suggested, this splits out the opcode lookup, and makes some
further tweaks that speed up powerpc disassembly a few percent.
* 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.
Index: opcodes/ppc-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/ppc-dis.c,v
retrieving revision 1.53
diff -u -p -r1.53 ppc-dis.c
--- opcodes/ppc-dis.c 15 Mar 2012 12:58:47 -0000 1.53
+++ opcodes/ppc-dis.c 16 Mar 2012 10:20:40 -0000
@@ -265,9 +265,7 @@ powerpc_init_dialect (struct disassemble
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 c
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);
--
Alan Modra
Australia Development Lab, IBM