From d302b5f240683111aa39bf23778705cd88a2a078 Mon Sep 17 00:00:00 2001 From: David Edelsohn Date: Wed, 3 Apr 1996 18:54:49 +0000 Subject: [PATCH] * sparc-dis.c (opcodes_initialized): Move inside print_insn_sparc. (current_arch_mask): New static global. (compute_arch_mask): New static function. (print_insn_sparc): Delete sparc_v9_p. New static local current_mach. Resort opcode table if current_mach changes. Generalize "insn not supported" test. (compare_opcodes): Prefer supported opcodes to nonsupported ones. Delete test for v9/!v9. * sparc-opc.c (MASK_*): Use SPARC_OPCODE_ARCH_MASK. (v6notlet): Define. (brfc): Split into CBR and FBR for coprocessor/fp branches. (brfcx): Renamed to FBRX. (condfc): Renamed to CONDFC. Pass v6notlet to CBR (standard coprocessor mnemonics are not supported on the sparclet). (condf): Renamed to CONDF. (SLCBCC2): Delete F_ALIAS flag. --- opcodes/ChangeLog | 19 +++++++ opcodes/sparc-dis.c | 95 ++++++++++++++++++++++++++--------- opcodes/sparc-opc.c | 119 ++++++++++++++++++++++++++------------------ 3 files changed, 161 insertions(+), 72 deletions(-) diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 34ae975c3cc..5bfbf2d2cb5 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,22 @@ +Wed Apr 3 10:40:45 1996 Doug Evans + + * sparc-dis.c (opcodes_initialized): Move inside print_insn_sparc. + (current_arch_mask): New static global. + (compute_arch_mask): New static function. + (print_insn_sparc): Delete sparc_v9_p. New static local + current_mach. Resort opcode table if current_mach changes. + Generalize "insn not supported" test. + (compare_opcodes): Prefer supported opcodes to nonsupported ones. + Delete test for v9/!v9. + * sparc-opc.c (MASK_*): Use SPARC_OPCODE_ARCH_MASK. + (v6notlet): Define. + (brfc): Split into CBR and FBR for coprocessor/fp branches. + (brfcx): Renamed to FBRX. + (condfc): Renamed to CONDFC. Pass v6notlet to CBR (standard + coprocessor mnemonics are not supported on the sparclet). + (condf): Renamed to CONDF. + (SLCBCC2): Delete F_ALIAS flag. + Sat Mar 30 21:45:59 1996 Doug Evans * sparc-opc.c (sparc_opcodes): rd must be 0 for diff --git a/opcodes/sparc-dis.c b/opcodes/sparc-dis.c index df2f6f0bf2a..18158818560 100644 --- a/opcodes/sparc-dis.c +++ b/opcodes/sparc-dis.c @@ -175,12 +175,14 @@ is_delayed_branch (insn) return 0; } -/* Nonzero of opcode table has been initialized. */ -static int opcodes_initialized = 0; - /* extern void qsort (); */ static int compare_opcodes (); +/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value + to compare_opcodes. */ +static unsigned int current_arch_mask; +static int compute_arch_mask (); + /* Print one instruction from MEMADDR on INFO->STREAM. We suffix the instruction with a comment that gives the absolute @@ -199,13 +201,19 @@ print_insn_sparc (memaddr, info) unsigned long insn; register unsigned int i; register struct opcode_hash *op; - int sparc_v9_p = bfd_mach_sparc_v9_p (info->mach); + /* Nonzero of opcode table has been initialized. */ + static int opcodes_initialized = 0; + /* bfd mach number of last call. */ + static unsigned long current_mach = 0; - if (!opcodes_initialized) + if (!opcodes_initialized + || info->mach != current_mach) { + current_arch_mask = compute_arch_mask (info->mach); qsort ((char *) sparc_opcodes, sparc_num_opcodes, sizeof (sparc_opcodes[0]), compare_opcodes); build_hash_table (sparc_opcodes, opcode_hash_table, sparc_num_opcodes); + current_mach = info->mach; opcodes_initialized = 1; } @@ -230,16 +238,8 @@ print_insn_sparc (memaddr, info) { CONST struct sparc_opcode *opcode = op->opcode; - /* ??? These architecture tests need to be more selective. */ - - /* If the current architecture isn't sparc64, skip sparc64 insns. */ - if (!sparc_v9_p - && V9_ONLY_P (opcode)) - continue; - - /* If the current architecture is sparc64, skip sparc32 only insns. */ - if (sparc_v9_p - && ! V9_P (opcode)) + /* If the insn isn't supported by the current architecture, skip it. */ + if (! (opcode->architecture & current_arch_mask)) continue; if ((opcode->match & insn) == opcode->match @@ -267,6 +267,10 @@ print_insn_sparc (memaddr, info) && strchr (opcode->args, 'r') != 0) /* Can't do simple format if source and dest are different. */ continue; + if (X_RS2 (insn) != X_RD (insn) + && strchr (opcode->args, 'O') != 0) + /* Can't do simple format if source and dest are different. */ + continue; (*info->fprintf_func) (stream, opcode->name); @@ -325,6 +329,7 @@ print_insn_sparc (memaddr, info) break; case '2': + case 'O': reg (X_RS2 (insn)); break; @@ -691,6 +696,34 @@ print_insn_sparc (memaddr, info) return sizeof (buffer); } +/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ + +static int +compute_arch_mask (unsigned long mach) +{ + switch (mach) + { + case 0 : + case bfd_mach_sparc : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8); + case bfd_mach_sparc_sparclet : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); + case bfd_mach_sparc_sparclite : + /* sparclites insns are recognized by default (because that's how + they've always been treated, for better or worse). Kludge this by + indicating generic v8 is also selected. */ + return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) + | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); + case bfd_mach_sparc_v8plus : + case bfd_mach_sparc_v9 : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); + case bfd_mach_sparc_v8plusa : + case bfd_mach_sparc_v9a : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); + } + abort (); +} + /* Compare opcodes A and B. */ static int @@ -703,6 +736,24 @@ compare_opcodes (a, b) unsigned long int lose0 = op0->lose, lose1 = op1->lose; register unsigned int i; + /* If one (and only one) insn isn't supported by the current architecture, + prefer the one that is. If neither are supported, but they're both for + the same architecture, continue processing. Otherwise (both unsupported + and for different architectures), prefer lower numbered arch's (fudged + by comparing the bitmasks). */ + if (op0->architecture & current_arch_mask) + { + if (! (op1->architecture & current_arch_mask)) + return -1; + } + else + { + if (op1->architecture & current_arch_mask) + return 1; + else if (op0->architecture != op1->architecture) + return op0->architecture - op1->architecture; + } + /* If a bit is set in both match and lose, there is something wrong with the opcode table. */ if (match0 & lose0) @@ -743,10 +794,6 @@ compare_opcodes (a, b) return x1 - x0; } - /* Put non-sparc64 insns ahead of sparc64 ones. */ - if (V9_ONLY_P (op0) != V9_ONLY_P (op1)) - return V9_ONLY_P (op0) - V9_ONLY_P (op1); - /* They are functionally equal. So as long as the opcode table is valid, we can put whichever one first we want, on aesthetic grounds. */ @@ -762,12 +809,14 @@ compare_opcodes (a, b) better have the same opcode. This is a sanity check on the table. */ i = strcmp (op0->name, op1->name); if (i) + { if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ - return i; + return i; else - fprintf (stderr, - "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n", - op0->name, op1->name); + fprintf (stderr, + "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n", + op0->name, op1->name); + } /* Fewer arguments are preferred. */ { diff --git a/opcodes/sparc-opc.c b/opcodes/sparc-opc.c index 6d4e84706d7..c4e22d458d5 100644 --- a/opcodes/sparc-opc.c +++ b/opcodes/sparc-opc.c @@ -29,18 +29,21 @@ Boston, MA 02111-1307, USA. */ #include "opcode/sparc.h" /* Some defines to make life easy. */ -#define MASK_V6 (1 << SPARC_OPCODE_ARCH_V6) -#define MASK_V7 (1 << SPARC_OPCODE_ARCH_V7) -#define MASK_V8 (1 << SPARC_OPCODE_ARCH_V8) -#define MASK_SPARCLET (1 << SPARC_OPCODE_ARCH_SPARCLET) -#define MASK_SPARCLITE (1 << SPARC_OPCODE_ARCH_SPARCLITE) -#define MASK_V9 (1 << SPARC_OPCODE_ARCH_V9) -#define MASK_V9A (1 << SPARC_OPCODE_ARCH_V9A) +#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) +#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7) +#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) +#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET) +#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) +#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9) +#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A) /* Bit masks of architectures supporting the insn. */ #define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ | MASK_SPARCLITE | MASK_V9 | MASK_V9A) +/* v6 insns not supported on the sparclet */ +#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A) #define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ | MASK_SPARCLITE | MASK_V9 | MASK_V9A) /* Although not all insns are implemented in hardware, sparclite is defined @@ -59,7 +62,9 @@ Boston, MA 02111-1307, USA. */ | MASK_SPARCLET | MASK_SPARCLITE) /* Table of opcode architectures. - The order is defined in opcode/sparc.h. */ + The order is defined in opcode/sparc.h. + The names must match the arguments to gas' -A option in tc-sparc.c. +*/ const struct sparc_opcode_arch sparc_opcode_archs[] = { { "v6", MASK_V6 }, { "v7", MASK_V6 | MASK_V7 }, @@ -67,6 +72,7 @@ const struct sparc_opcode_arch sparc_opcode_archs[] = { { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET }, { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE }, /* ??? Don't some v8 priviledged insns conflict with v9? */ + /* ??? Will we want v8plus{,a} entries? */ { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 }, /* v9 with ultrasparc additions */ { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A }, @@ -979,12 +985,12 @@ cond ("bcc", "tcc", CONDCC, F_CONDBR), cond ("bcs", "tcs", CONDCS, F_CONDBR), cond ("be", "te", CONDE, F_CONDBR), cond ("bg", "tg", CONDG, F_CONDBR), -cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), +cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), cond ("bge", "tge", CONDGE, F_CONDBR), cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */ cond ("bgu", "tgu", CONDGU, F_CONDBR), cond ("bl", "tl", CONDL, F_CONDBR), -cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), +cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), cond ("ble", "tle", CONDLE, F_CONDBR), cond ("bleu", "tleu", CONDLEU, F_CONDBR), cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */ @@ -1249,11 +1255,18 @@ cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ #undef FM_QF /* v9 */ #undef FM_SF /* v9 */ -#define brfc(opcode, mask, lose, flags) \ +/* Coprocessor branches. */ +#define CBR(opcode, mask, lose, flags, arch) \ + { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, arch }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, arch } + +/* Floating point branches. */ +#define FBR(opcode, mask, lose, flags) \ { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, v6 }, \ { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, v6 } -#define brfcx(opcode, mask, lose, flags) /* v9 */ \ +/* V9 extended floating point branches. */ +#define FBRX(opcode, mask, lose, flags) /* v9 */ \ { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), "6,G", flags|F_DELAYED, v9 }, \ { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), ",T 6,G", flags|F_DELAYED, v9 }, \ { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a 6,G", flags|F_DELAYED, v9 }, \ @@ -1279,43 +1292,51 @@ cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G", flags|F_DELAYED, v9 }, \ { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED, v9 } -/* v9: We must put `brfcx' before `brfc', to ensure that we never match +/* v9: We must put `FBRX' before `FBR', to ensure that we never match v9: something against an expression unless it is an expression. Otherwise, v9: we end up with undefined symbol tables entries, because they get added, v9: but are not deleted if the pattern fails to match. */ -#define condfc(fop, cop, mask, flags) \ - brfcx(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ - brfc(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ - brfc(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags) - -#define condf(fop, mask, flags) \ - brfcx(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ - brfc(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags) - -condfc("fb", "cb", 0x8, 0), -condfc("fba", "cba", 0x8, F_ALIAS), -condfc("fbe", "cb0", 0x9, 0), -condf("fbz", 0x9, F_ALIAS), -condfc("fbg", "cb2", 0x6, 0), -condfc("fbge", "cb02", 0xb, 0), -condfc("fbl", "cb1", 0x4, 0), -condfc("fble", "cb01", 0xd, 0), -condfc("fblg", "cb12", 0x2, 0), -condfc("fbn", "cbn", 0x0, 0), -condfc("fbne", "cb123", 0x1, 0), -condf("fbnz", 0x1, F_ALIAS), -condfc("fbo", "cb012", 0xf, 0), -condfc("fbu", "cb3", 0x7, 0), -condfc("fbue", "cb03", 0xa, 0), -condfc("fbug", "cb23", 0x5, 0), -condfc("fbuge", "cb023", 0xc, 0), -condfc("fbul", "cb13", 0x3, 0), -condfc("fbule", "cb013", 0xe, 0), - -#undef condfc -#undef brfc -#undef brfcx /* v9 */ +#define CONDFC(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6notlet) + +#define CONDFCL(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6) + +#define CONDF(fop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags) + +CONDFC ("fb", "cb", 0x8, 0), +CONDFCL ("fba", "cba", 0x8, F_ALIAS), +CONDFC ("fbe", "cb0", 0x9, 0), +CONDF ("fbz", 0x9, F_ALIAS), +CONDFC ("fbg", "cb2", 0x6, 0), +CONDFC ("fbge", "cb02", 0xb, 0), +CONDFC ("fbl", "cb1", 0x4, 0), +CONDFC ("fble", "cb01", 0xd, 0), +CONDFC ("fblg", "cb12", 0x2, 0), +CONDFCL ("fbn", "cbn", 0x0, 0), +CONDFC ("fbne", "cb123", 0x1, 0), +CONDF ("fbnz", 0x1, F_ALIAS), +CONDFC ("fbo", "cb012", 0xf, 0), +CONDFC ("fbu", "cb3", 0x7, 0), +CONDFC ("fbue", "cb03", 0xa, 0), +CONDFC ("fbug", "cb23", 0x5, 0), +CONDFC ("fbuge", "cb023", 0xc, 0), +CONDFC ("fbul", "cb13", 0x3, 0), +CONDFC ("fbule", "cb013", 0xe, 0), + +#undef CONDFC +#undef CONDFCL +#undef CONDF +#undef CBR +#undef FBR +#undef FBRX /* v9 */ { "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ { "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ @@ -1516,14 +1537,14 @@ COMMUTEOP ("smuld", 0x0d, sparclet), { "cpull", F3(2, 0x36, 0)|ASI(2), F3(~2, ~0x36, ~0)|ASI(~2)|RS1(~0)|RS2(~0), "d", 0, sparclet }, /* sparclet coprocessor branch insns */ -/* FIXME: We have to mark these as aliases until we can sort opcodes based - on selected cpu. */ #define SLCBCC2(opcode, mask, lose) \ - { opcode, (mask), ANNUL|(lose), "l", F_DELAYED|F_CONDBR|F_ALIAS, sparclet }, \ - { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR|F_ALIAS, sparclet } + { opcode, (mask), ANNUL|(lose), "l", F_DELAYED|F_CONDBR, sparclet }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR, sparclet } #define SLCBCC(opcode, mask) \ SLCBCC2(opcode, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask))) +/* cbn,cba can't be defined here because they're defined elsewhere and GAS + requires all mnemonics of the same name to be consecutive. */ /*SLCBCC("cbn", 0), - already defined */ SLCBCC("cbe", 1), SLCBCC("cbf", 2), -- 2.30.2