]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Optimize x86/x86-64 disassembler tables.
authorUlrich Drepper <drepper@redhat.com>
Fri, 2 Jan 2009 04:18:48 +0000 (20:18 -0800)
committerUlrich Drepper <drepper@redhat.com>
Fri, 2 Jan 2009 04:18:48 +0000 (20:18 -0800)
libcpu/ChangeLog
libcpu/i386_disasm.c
libcpu/i386_parse.y

index 4b94d26ad9e174726b1c681ff2b21e269d5634f3..a043e45f4606f9b6fc308525ec47db9a36e0028e 100644 (file)
@@ -1,5 +1,9 @@
 2009-01-01  Ulrich Drepper  <drepper@redhat.com>
 
+       * i386_parse.y (instrtable_out): Optimize match_data table by not
+       emitting 0xff masks for leading bytes.
+       * i386_disasm.c (i386_disasm): Adjust reader of match_data.
+
        * i386_disasm.c (i386_disasm): Reset bufcnt when not matched.  We
        don't expect snprintf to fail.
 
index a656cdb4bbc9dd875fb6661c76c48a9885779461..c6bb0a584f80b39e55da256f2a34dd338bac2534 100644 (file)
@@ -1,5 +1,5 @@
 /* Disassembler for x86.
-   Copyright (C) 2007, 2008 Red Hat, Inc.
+   Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2007.
 
@@ -376,37 +376,49 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
       while (curr < match_end)
        {
          uint_fast8_t len = *curr++;
-         const uint8_t *start = curr;
+         uint_fast8_t clen = len >> 4;
+         len &= 0xf;
+         const uint8_t *next_curr = curr + clen + (len - clen) * 2;
 
          assert (len > 0);
-         assert (curr + 2 * len <= match_end);
+         assert (curr + clen + 2 * (len - clen) <= match_end);
 
          const uint8_t *codep = data;
          int correct_prefix = 0;
          int opoff = 0;
 
-         if (data > begin && codep[-1] == curr[1] && curr[0] == 0xff)
+         if (data > begin && codep[-1] == *curr && clen > 0)
            {
              /* We match a prefix byte.  This is exactly one byte and
                 is matched exactly, without a mask.  */
              --len;
-             start += 2;
+             --clen;
              opoff = 8;
 
-             curr += 2;
+             ++curr;
 
              assert (last_prefix_bit != 0);
              correct_prefix = last_prefix_bit;
            }
 
          size_t avail = len;
+         while (clen > 0)
+           {
+             if (*codep++ != *curr++)
+               goto not;
+             --avail;
+             --clen;
+             if (codep == end && avail > 0)
+               goto do_ret;
+           }
+
          while (avail > 0)
            {
              uint_fast8_t masked = *codep++ & *curr++;
              if (masked != *curr++)
                {
                not:
-                 curr = start + 2 * len;
+                 curr = next_curr;
                  ++cnt;
                  bufcnt = 0;
                  goto next_match;
@@ -459,7 +471,7 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
                 are not used uninitialized.  */
              asm (""
                   : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
-                    "=mr" (start), "=mr" (len));
+                    "=mr" (next_curr), "=mr" (len));
            }
 
          size_t prefix_size = 0;
index b3a684d6e00ab900087d3df8061519c5337b39d6..bea0e335856b6b3b43d13bb5162fc58711916fce 100644 (file)
@@ -1,6 +1,6 @@
 %{
 /* Parser for i386 CPU description.
-   Copyright (C) 2004, 2005, 2007, 2008 Red Hat, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008, 2009 Red Hat, Inc.
    Written by Ulrich Drepper <drepper@redhat.com>, 2004.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -37,6 +37,7 @@
 #include <math.h>
 #include <obstack.h>
 #include <search.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -1248,6 +1249,8 @@ instrtable_out (void)
       /* First count the number of bytes.  */
       size_t totalbits = 0;
       size_t zerobits = 0;
+      bool leading_p = true;
+      size_t leadingbits = 0;
       struct bitvalue *b = instr->bytes;
       while (b != NULL)
        {
@@ -1255,6 +1258,8 @@ instrtable_out (void)
            {
              ++totalbits;
              zerobits = 0;
+             if (leading_p)
+               ++leadingbits;
            }
          else
            {
@@ -1264,13 +1269,15 @@ instrtable_out (void)
                zerobits = 0;
              else
                zerobits += b->field->bits;
+             leading_p = false;
            }
          b = b->next;
        }
       size_t nbytes = (totalbits - zerobits + 7) / 8;
       assert (nbytes > 0);
+      size_t leadingbytes = leadingbits / 8;
 
-      fprintf (outfile, "  %#zx,", nbytes);
+      fprintf (outfile, "  %#zx,", nbytes | (leadingbytes << 4));
 
       /* Now create the mask and byte values.  */
       uint8_t byte = 0;
@@ -1285,7 +1292,15 @@ instrtable_out (void)
              mask = (mask << 1) | 1;
              if (++nbits == 8)
                {
-                 fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",", mask, byte);
+                 if (leadingbytes > 0)
+                   {
+                     assert (mask == 0xff);
+                     fprintf (outfile, " %#" PRIx8 ",", byte);
+                     --leadingbytes;
+                   }
+                 else
+                   fprintf (outfile, " %#" PRIx8 ", %#" PRIx8 ",",
+                            mask, byte);
                  byte = mask = nbits = 0;
                  if (--nbytes == 0)
                    break;
@@ -1293,6 +1308,8 @@ instrtable_out (void)
            }
          else
            {
+             assert (leadingbytes == 0);
+
              unsigned long int remaining = b->field->bits;
              while (nbits + remaining > 8)
                {