aboutsummaryrefslogtreecommitdiff
path: root/opcodes/sparc-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/sparc-dis.c')
-rw-r--r--opcodes/sparc-dis.c95
1 files changed, 72 insertions, 23 deletions
diff --git a/opcodes/sparc-dis.c b/opcodes/sparc-dis.c
index df2f6f0..1815881 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. */
{