summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-01-01 20:18:48 -0800
committerUlrich Drepper <drepper@redhat.com>2009-01-01 20:18:48 -0800
commit92287fdf5b21438a3aa3d7094527b5cf870d1af6 (patch)
tree13bda71cbd646fdbaa6c9188d67166cade8d7ea4 /libcpu
parent44173edad1dfd24c4d98fcf032308f7df28db652 (diff)
downloadelfutils-92287fdf5b21438a3aa3d7094527b5cf870d1af6.tar.gz
Optimize x86/x86-64 disassembler tables.
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/ChangeLog4
-rw-r--r--libcpu/i386_disasm.c28
-rw-r--r--libcpu/i386_parse.y23
3 files changed, 44 insertions, 11 deletions
diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog
index 4b94d26a..a043e45f 100644
--- a/libcpu/ChangeLog
+++ b/libcpu/ChangeLog
@@ -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.
diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c
index a656cdb4..c6bb0a58 100644
--- a/libcpu/i386_disasm.c
+++ b/libcpu/i386_disasm.c
@@ -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;
diff --git a/libcpu/i386_parse.y b/libcpu/i386_parse.y
index b3a684d6..bea0e335 100644
--- a/libcpu/i386_parse.y
+++ b/libcpu/i386_parse.y
@@ -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)
{