From 92287fdf5b21438a3aa3d7094527b5cf870d1af6 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 1 Jan 2009 20:18:48 -0800 Subject: Optimize x86/x86-64 disassembler tables. --- libcpu/ChangeLog | 4 ++++ libcpu/i386_disasm.c | 28 ++++++++++++++++++++-------- libcpu/i386_parse.y | 23 ++++++++++++++++++++--- 3 files changed, 44 insertions(+), 11 deletions(-) (limited to 'libcpu') 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 + * 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 , 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 , 2004. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -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) { -- cgit v1.2.1