2012-03-14 James Lemke include/opcode/ * ppc.h (PPC_OPCD_SEGS, PPC_OP_TO_SEG): New. opcodes/ * ppc-dis.c (ppc_opcd_indices_calc): New. (print_insn_powerpc): Modify search starting point. diff -ru -X /home/jwlemke/bin/diffexcl binutils-0/include/opcode/ppc.h binutils/include/opcode/ppc.h --- binutils-0/include/opcode/ppc.h 2012-03-09 15:39:02.000000000 -0800 +++ binutils/include/opcode/ppc.h 2012-03-13 16:54:15.711000146 -0700 @@ -185,6 +185,10 @@ /* A macro to extract the major opcode from an instruction. */ #define PPC_OP(i) (((i) >> 26) & 0x3f) + +/* Macros to help with searching the opcode table by segment. */ +#define PPC_OPCD_SEGS 16 +#define PPC_OP_TO_SEG(i) ((i) >> 2) /* The operands table is an array of struct powerpc_operand. */ diff -ru -X /home/jwlemke/bin/diffexcl binutils-0/opcodes/ppc-dis.c binutils/opcodes/ppc-dis.c --- binutils-0/opcodes/ppc-dis.c 2012-03-09 15:39:02.000000000 -0800 +++ binutils/opcodes/ppc-dis.c 2012-03-13 17:01:25.375000146 -0700 @@ -345,6 +345,39 @@ return 1; } +/* Calculate opcode table indices to speed up disassembly. + + The opcode table is sorted by major opcode. Most insns have a major opcode + that is the the most-significat 6 bits. However for some (e.g. VLE) the + opcode is as small as the 4 MSBs. Therefore we segment the table into 16 + pieces based on the 4 MSBs of the major opcode. + Searches will start at one of the segment boundaries. */ + +static void +ppc_opcd_indices_calc (unsigned short int **ppc_opcd_indices) +{ + int i; + unsigned long op; + unsigned short prev_seg, seg; + static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS]; + + for (i = 0; i < PPC_OPCD_SEGS; ++i) + powerpc_opcd_indices[i] = powerpc_num_opcodes - 1; + + prev_seg = 0x3fff; + for (i = 0; i < powerpc_num_opcodes; ++i) + { + op = PPC_OP(powerpc_opcodes[i].opcode); + seg = PPC_OP_TO_SEG(op); + if (seg != prev_seg) + { + powerpc_opcd_indices[seg] = i; + prev_seg = seg; + } + } + *ppc_opcd_indices = &powerpc_opcd_indices[0]; +} + /* Print a PowerPC or POWER instruction. */ static int @@ -359,6 +392,7 @@ const struct powerpc_opcode *opcode; const struct powerpc_opcode *opcode_end; unsigned long op; + static unsigned short *ppc_opcd_indices = NULL; status = (*info->read_memory_func) (memaddr, buffer, 4, info); if (status != 0) @@ -375,11 +409,16 @@ /* Get the major opcode of the instruction. */ op = PPC_OP (insn); - /* Find the first match in the opcode table. We could speed this up - a bit by doing a binary search on the major opcode. */ + /* 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; + if (ppc_opcd_indices == NULL) + ppc_opcd_indices_calc (&ppc_opcd_indices); again: - for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) + for (opcode = powerpc_opcodes + ppc_opcd_indices [PPC_OP_TO_SEG(op)]; + opcode < opcode_end; + ++opcode) { unsigned long table_op; const unsigned char *opindex; @@ -390,10 +429,10 @@ int skip_optional; table_op = PPC_OP (opcode->opcode); - if (op < table_op) - break; if (op > table_op) continue; + if (op < table_op) + break; if ((insn & opcode->mask) != opcode->opcode || (opcode->flags & dialect) == 0