diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 5 | ||||
-rw-r--r-- | gas/config/tc-ppc.c | 56 |
2 files changed, 52 insertions, 9 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index e9419a3..bb8a91e 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2008-03-07 Alan Modra <amodra@bigpond.net.au> + + * config/tc-ppc.c (ppc_setup_opcodes): Tidy. Add code to test + for strict ordering of powerpc_opcodes, but disable for now. + 2008-03-04 Paul Brook <paul@codesourcery.com> * config/tc-arm.c (arm_ext_barrier, arm_ext_msr): New. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 3ca161b..5c1252c 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -1255,7 +1255,6 @@ ppc_setup_opcodes (void) const struct powerpc_macro *macro; const struct powerpc_macro *macro_end; bfd_boolean bad_insn = FALSE; - unsigned long prev_opcode = 0; if (ppc_hash != NULL) hash_die (ppc_hash); @@ -1303,17 +1302,56 @@ ppc_setup_opcodes (void) { const unsigned char *o; unsigned long omask = op->mask; - unsigned long major_opcode = PPC_OP (op->opcode); - /* The major opcodes had better be sorted. Code in the disassembler - assumes the insns are sorted according to major opcode. */ - if (major_opcode < prev_opcode) + if (op != powerpc_opcodes) { - as_bad (_("major opcode is not sorted for %s"), - op->name); - bad_insn = TRUE; + /* The major opcodes had better be sorted. Code in the + disassembler assumes the insns are sorted according to + major opcode. */ + if (PPC_OP (op[0].opcode) < PPC_OP (op[-1].opcode)) + { + as_bad (_("major opcode is not sorted for %s"), + op->name); + bad_insn = TRUE; + } + + /* Warn if the table isn't more strictly ordered. + Unfortunately it doesn't seem possible to order the + table on much more than the major opcode, which makes + it difficult to implement a binary search in the + disassembler. The problem is that we have multiple + ways to disassemble instructions, and we usually want + to choose a more specific form (with more bits set in + the opcode) than a more general form. eg. all of the + following are equivalent: + bne label # opcode = 0x40820000, mask = 0xff830003 + bf 2,label # opcode = 0x40800000, mask = 0xff800003 + bc 4,2,label # opcode = 0x40000000, mask = 0xfc000003 + + There are also cases where the table needs to be out + of order to disassemble the correct instruction for + processor variants. eg. "lhae" booke64 insn must be + found before "ld" ppc64 insn. */ + else if (0) + { + unsigned long t1 = op[0].opcode; + unsigned long t2 = op[-1].opcode; + + if (((t1 ^ t2) & 0xfc0007ff) == 0 + && (t1 & 0xfc0006df) == 0x7c000286) + { + /* spr field is split. */ + t1 = ((t1 & ~0x1ff800) + | ((t1 & 0xf800) << 5) | ((t1 & 0x1f0000) >> 5)); + t2 = ((t2 & ~0x1ff800) + | ((t2 & 0xf800) << 5) | ((t2 & 0x1f0000) >> 5)); + } + if (t1 < t2) + as_warn (_("%s (%08lx %08lx) after %s (%08lx %08lx)"), + op[0].name, op[0].opcode, op[0].mask, + op[-1].name, op[-1].opcode, op[-1].mask); + } } - prev_opcode = major_opcode; /* The mask had better not trim off opcode bits. */ if ((op->opcode & omask) != op->opcode) |