* 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.
This commit is contained in:
David Edelsohn 1996-04-03 18:54:49 +00:00
parent d1f74cd2c3
commit d302b5f240
3 changed files with 158 additions and 69 deletions

View File

@ -1,3 +1,22 @@
Wed Apr 3 10:40:45 1996 Doug Evans <dje@canuck.cygnus.com>
* 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 <dje@canuck.cygnus.com>
* sparc-opc.c (sparc_opcodes): rd must be 0 for

View File

@ -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. */
{

View File

@ -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<arch> 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 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 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)
#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)
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),
#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)
#undef condfc
#undef brfc
#undef brfcx /* v9 */
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),