Put the qsort() back in in sparc-pinsn.c
authorPer Bothner <per@bothner.com>
Wed, 29 Jan 1992 01:33:48 +0000 (01:33 +0000)
committerPer Bothner <per@bothner.com>
Wed, 29 Jan 1992 01:33:48 +0000 (01:33 +0000)
gdb/ChangeLog
gdb/sparc-pinsn.c

index 0169cc480dd9fbe2c27c2bf29181947165c06af3..80336bed5f8c405fb6c48d0ef3eda9a4ebeeebb1 100644 (file)
@@ -1,3 +1,7 @@
+Tue Jan 28 17:32:13 1992  Per Bothner  (bothner at cygnus.com)
+
+       * sparc-pinsn.c:  Put the qsort() back in.
+
 Mon Jan 27 18:51:03 1992  John Gilmore  (gnu at cygnus.com)
 
        * findvar.c (read_register, write_register):  Handle machines
index ba2237b575ba73946ef5f0c98df5e152d469d3db..3fddb13a1f42d247f98252ebadff8e2aaeb8d0f5 100644 (file)
@@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "string.h"
 #include "target.h"
 
+#define SORT_NEEDED
+
 extern char *reg_names[];
 #define        freg_names      (&reg_names[4 * 8])
 
@@ -89,6 +91,11 @@ is_delayed_branch (insn)
   return 0;
 }
 
+#ifdef SORT_NEEDED
+static int opcodes_sorted = 0;
+extern void qsort ();
+#endif
+
 /* Print one instruction from MEMADDR on STREAM.  */
 int
 print_insn (memaddr, stream)
@@ -99,6 +106,16 @@ print_insn (memaddr, stream)
 
   register unsigned int i;
 
+#ifdef SORT_NEEDED
+  if (!opcodes_sorted)
+    {
+      static int compare_opcodes ();
+      qsort ((char *) sparc_opcodes, NUMOPCODES,
+            sizeof (sparc_opcodes[0]), compare_opcodes);
+      opcodes_sorted = 1;
+    }
+#endif
+
   read_memory (memaddr, &insn, sizeof (insn));
 
   for (i = 0; i < NUMOPCODES; ++i)
@@ -178,14 +195,20 @@ print_insn (memaddr, stream)
 
 #define        freg(n) fprintf_filtered (stream, "%%%s", freg_names[n])
                  case 'e':
+                 case 'v':     /* double/even */
+                 case 'V':     /* quad/multiple of 4 */
                    freg (insn.rs1);
                    break;
 
                  case 'f':
+                 case 'B':     /* double/even */
+                 case 'R':     /* quad/multiple of 4 */
                    freg (insn.rs2);
                    break;
 
                  case 'g':
+                 case 'H':     /* double/even */
+                 case 'J':     /* quad/multiple of 4 */
                    freg (insn.rd);
                    break;
 #undef freg
@@ -346,3 +369,113 @@ print_insn (memaddr, stream)
   printf_filtered ("%#8x", insn.code);
   return sizeof (insn);
 }
+
+#ifdef SORT_NEEDED
+/* Compare opcodes A and B.  */
+
+static int
+compare_opcodes (a, b)
+     char *a, *b;
+{
+  struct sparc_opcode *op0 = (struct sparc_opcode *) a;
+  struct sparc_opcode *op1 = (struct sparc_opcode *) b;
+  unsigned long int match0 = op0->match, match1 = op1->match;
+  unsigned long int lose0 = op0->lose, lose1 = op1->lose;
+  register unsigned int i;
+
+  /* If a bit is set in both match and lose, there is something
+     wrong with the opcode table.  */
+  if (match0 & lose0)
+    {
+      fprintf (stderr, "Internal error:  bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+              op0->name, match0, lose0);
+      op0->lose &= ~op0->match;
+      lose0 = op0->lose;
+    }
+
+  if (match1 & lose1)
+    {
+      fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+              op1->name, match1, lose1);
+      op1->lose &= ~op1->match;
+      lose1 = op1->lose;
+    }
+
+  /* Because the bits that are variable in one opcode are constant in
+     another, it is important to order the opcodes in the right order.  */
+  for (i = 0; i < 32; ++i)
+    {
+      unsigned long int x = 1 << i;
+      int x0 = (match0 & x) != 0;
+      int x1 = (match1 & x) != 0;
+
+      if (x0 != x1)
+       return x1 - x0;
+    }
+
+  for (i = 0; i < 32; ++i)
+    {
+      unsigned long int x = 1 << i;
+      int x0 = (lose0 & x) != 0;
+      int x1 = (lose1 & x) != 0;
+
+      if (x0 != x1)
+       return x1 - x0;
+    }
+
+  /* They are functionally equal.  So as long as the opcode table is
+     valid, we can put whichever one first we want, on aesthetic grounds.  */
+
+  /* Our first aesthetic ground is that aliases defer to real insns.  */
+  {
+    int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
+    if (alias_diff != 0)
+      /* Put the one that isn't an alias first.  */
+      return alias_diff;
+  }
+
+  /* Except for aliases, two "identical" instructions had
+     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;
+      else
+         fprintf (stderr,
+                  "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n",
+                  op0->name, op1->name);
+
+  /* Fewer arguments are preferred.  */
+  {
+    int length_diff = strlen (op0->args) - strlen (op1->args);
+    if (length_diff != 0)
+      /* Put the one with fewer arguments first.  */
+      return length_diff;
+  }
+
+  /* Put 1+i before i+1.  */
+  {
+    char *p0 = (char *) strchr(op0->args, '+');
+    char *p1 = (char *) strchr(op1->args, '+');
+
+    if (p0 && p1)
+      {
+       /* There is a plus in both operands.  Note that a plus
+          sign cannot be the first character in args,
+          so the following [-1]'s are valid.  */
+       if (p0[-1] == 'i' && p1[1] == 'i')
+         /* op0 is i+1 and op1 is 1+i, so op1 goes first.  */
+         return 1;
+       if (p0[1] == 'i' && p1[-1] == 'i')
+         /* op0 is 1+i and op1 is i+1, so op0 goes first.  */
+         return -1;
+      }
+  }
+
+  /* They are, as far as we can tell, identical.
+     Since qsort may have rearranged the table partially, there is
+     no way to tell which one was first in the opcode table as
+     written, so just say there are equal.  */
+  return 0;
+}
+#endif