Break apart perfect hash lookup generation and x86 arch-specific

instruction handling.

Use the GNU gperf file format, but continue to use our custom minimal
perfect hash generator.

svn path=/trunk/yasm/; revision=1929
0.6.2
Peter Johnson 18 years ago
parent 32921a0d12
commit 00e958bcf6
  1. 52
      modules/arch/x86/Makefile.inc
  2. 240
      modules/arch/x86/x86cpu.gperf
  3. 197
      modules/arch/x86/x86geninsn.c
  4. 107
      modules/arch/x86/x86id.c
  5. 311
      modules/arch/x86/x86insn.in
  6. 274
      modules/arch/x86/x86regtmod.gperf
  7. 4
      tools/Makefile.inc
  8. 34
      tools/gap/Makefile.inc
  9. 854
      tools/gap/gap.c
  10. 34
      tools/genperf/Makefile.inc
  11. 519
      tools/genperf/genperf.c
  12. 20
      tools/genperf/perfect.c
  13. 0
      tools/genperf/perfect.h
  14. 0
      tools/genperf/standard.h

@ -5,18 +5,58 @@ libyasm_a_SOURCES += modules/arch/x86/x86arch.h
libyasm_a_SOURCES += modules/arch/x86/x86bc.c
libyasm_a_SOURCES += modules/arch/x86/x86expr.c
libyasm_a_SOURCES += modules/arch/x86/x86id.c
libyasm_a_SOURCES += x86cpu.c
libyasm_a_SOURCES += x86regtmod.c
YASM_MODULES += arch_x86
modules/arch/x86/x86id.c: x86parse.c
modules/arch/x86/x86id.c: x86insn_nasm.c x86insn_gas.c
EXTRA_DIST += modules/arch/x86/x86parse.gap
noinst_PROGRAMS += x86geninsn
x86parse.c: $(srcdir)/modules/arch/x86/x86parse.gap gap$(EXEEXT)
$(top_builddir)/gap$(EXEEXT) $(srcdir)/modules/arch/x86/x86parse.gap $@
x86geninsn_SOURCES =
EXTRA_DIST += modules/arch/x86/x86geninsn.c
x86geninsn_LDADD = x86geninsn.$(OBJEXT)
x86geninsn_LINK = $(CCLD_FOR_BUILD) -o $@
BUILT_SOURCES += x86parse.c
CLEANFILES += x86parse.c
x86geninsn.$(OBJEXT): modules/arch/x86/x86geninsn.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f modules/arch/x86/x86geninsn.c || echo '$(srcdir)/'`modules/arch/x86/x86geninsn.c
EXTRA_DIST += modules/arch/x86/x86insn.in
x86insn_nasm.gperf x86insn_gas.gperf: $(srcdir)/modules/arch/x86/x86insn.in x86geninsn$(EXEEXT)
$(top_builddir)/x86geninsn$(EXEEXT) $(srcdir)/modules/arch/x86/x86insn.in x86insn_nasm.gperf x86insn_gas.gperf
BUILT_SOURCES += x86insn_nasm.gperf
BUILT_SOURCES += x86insn_gas.gperf
CLEANFILES += x86insn_nasm.gperf
CLEANFILES += x86insn_gas.gperf
EXTRA_DIST += modules/arch/x86/x86cpu.gperf
EXTRA_DIST += modules/arch/x86/x86regtmod.gperf
x86insn_nasm.c: x86insn_nasm.gperf genperf$(EXEEXT)
$(top_builddir)/genperf$(EXEEXT) x86insn_nasm.gperf > $@
x86insn_gas.c: x86insn_gas.gperf genperf$(EXEEXT)
$(top_builddir)/genperf$(EXEEXT) x86insn_gas.gperf > $@
x86cpu.c: $(srcdir)/modules/arch/x86/x86cpu.gperf genperf$(EXEEXT)
$(top_builddir)/genperf$(EXEEXT) $(srcdir)/modules/arch/x86/x86cpu.gperf > $@
x86regtmod.c: $(srcdir)/modules/arch/x86/x86regtmod.gperf genperf$(EXEEXT)
$(top_builddir)/genperf$(EXEEXT) $(srcdir)/modules/arch/x86/x86regtmod.gperf > $@
BUILT_SOURCES += x86insn_nasm.c
BUILT_SOURCES += x86insn_gas.c
BUILT_SOURCES += x86cpu.c
BUILT_SOURCES += x86regtmod.c
CLEANFILES += x86insn_nasm.c
CLEANFILES += x86insn_gas.c
CLEANFILES += x86cpu.c
CLEANFILES += x86cpu.c
CLEANFILES += x86regtmod.c
EXTRA_DIST += modules/arch/x86/tests/Makefile.inc

@ -0,0 +1,240 @@
#
# x86 CPU recognition
#
# Copyright (C) 2002-2007 Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
%{
#include <util.h>
RCSID("$Id$");
#include <libyasm.h>
#include <libyasm/phash.h>
#include "modules/arch/x86/x86arch.h"
enum cpu_mode {
CPU_MODE_VERBATIM = 1,
CPU_MODE_SET,
CPU_MODE_CLEAR
};
#define PROC_186 CPU_186|CPU_Priv
#define PROC_286 CPU_186|CPU_286|CPU_Priv
#define PROC_386 CPU_186|CPU_286|CPU_386|CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_486 CPU_186|CPU_286|CPU_386|CPU_486|CPU_FPU|CPU_SMM|\
CPU_Prot|CPU_Priv
#define PROC_586 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_FPU|\
CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_686 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_FPU|CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_p2 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_FPU|CPU_MMX|CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_p3 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_P3|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SMM|CPU_Prot|\
CPU_Priv
#define PROC_p4 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_P3|CPU_P4|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|\
CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_ia64 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_P3|CPU_P4|CPU_IA64|CPU_FPU|CPU_MMX|CPU_SSE|\
CPU_SSE2|CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_k6 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_K6|CPU_FPU|CPU_MMX|CPU_3DNow|CPU_SMM|CPU_Prot|\
CPU_Priv
#define PROC_k7 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_K6|CPU_Athlon|CPU_FPU|CPU_MMX|CPU_SSE|CPU_3DNow|\
CPU_SMM|CPU_Prot|CPU_Priv
#define PROC_hammer CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_K6|CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_3DNow|CPU_SMM|CPU_Prot|\
CPU_Priv
#define PROC_prescott CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SMM|\
CPU_Prot|CPU_Priv
#define PROC_conroe CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SMM|\
CPU_Prot|CPU_Priv
#define PROC_penryn CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE41|CPU_SMM|\
CPU_Prot|CPU_Priv
#define PROC_nehalem CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE41|\
CPU_SSE42|CPU_SMM|CPU_Prot|CPU_Priv
%}
%ignore-case
%language=ANSI-C
%compare-strncmp
%readonly-tables
%enum
%struct-type
%define hash-function-name cpu_hash
%define lookup-function-name cpu_find
struct cpu_parse_data {
const char *name;
enum cpu_mode mode;
unsigned long cpu;
};
%%
8086, CPU_MODE_VERBATIM, CPU_Priv
186, CPU_MODE_VERBATIM, PROC_186
80186, CPU_MODE_VERBATIM, PROC_186
i186, CPU_MODE_VERBATIM, PROC_186
286, CPU_MODE_VERBATIM, PROC_286
80286, CPU_MODE_VERBATIM, PROC_286
i286, CPU_MODE_VERBATIM, PROC_286
386, CPU_MODE_VERBATIM, PROC_386
80386, CPU_MODE_VERBATIM, PROC_386
i386, CPU_MODE_VERBATIM, PROC_386
486, CPU_MODE_VERBATIM, PROC_486
80486, CPU_MODE_VERBATIM, PROC_486
i486, CPU_MODE_VERBATIM, PROC_486
586, CPU_MODE_VERBATIM, PROC_586
i586, CPU_MODE_VERBATIM, PROC_586
pentium, CPU_MODE_VERBATIM, PROC_586
p5, CPU_MODE_VERBATIM, PROC_586
686, CPU_MODE_VERBATIM, PROC_686
i686, CPU_MODE_VERBATIM, PROC_686
p6, CPU_MODE_VERBATIM, PROC_686
ppro, CPU_MODE_VERBATIM, PROC_686
pentiumpro, CPU_MODE_VERBATIM, PROC_686
p2, CPU_MODE_VERBATIM, PROC_p2
pentium2, CPU_MODE_VERBATIM, PROC_p2
pentium-2, CPU_MODE_VERBATIM, PROC_p2
pentiumii, CPU_MODE_VERBATIM, PROC_p2
pentium-ii, CPU_MODE_VERBATIM, PROC_p2
p3, CPU_MODE_VERBATIM, PROC_p3
pentium3, CPU_MODE_VERBATIM, PROC_p3
pentium-3, CPU_MODE_VERBATIM, PROC_p3
pentiumiii, CPU_MODE_VERBATIM, PROC_p3
pentium-iii, CPU_MODE_VERBATIM, PROC_p3
katmai, CPU_MODE_VERBATIM, PROC_p3
p4, CPU_MODE_VERBATIM, PROC_p4
pentium4, CPU_MODE_VERBATIM, PROC_p4
pentium-4, CPU_MODE_VERBATIM, PROC_p4
pentiumiv, CPU_MODE_VERBATIM, PROC_p4
pentium-iv, CPU_MODE_VERBATIM, PROC_p4
williamette, CPU_MODE_VERBATIM, PROC_p4
ia64, CPU_MODE_VERBATIM, PROC_ia64
ia-64, CPU_MODE_VERBATIM, PROC_ia64
itanium, CPU_MODE_VERBATIM, PROC_ia64
k6, CPU_MODE_VERBATIM, PROC_k6
k7, CPU_MODE_VERBATIM, PROC_k7
athlon, CPU_MODE_VERBATIM, PROC_k7
hammer, CPU_MODE_VERBATIM, PROC_hammer
sledgehammer, CPU_MODE_VERBATIM, PROC_hammer
opteron, CPU_MODE_VERBATIM, PROC_hammer
athlon64, CPU_MODE_VERBATIM, PROC_hammer
athlon-64, CPU_MODE_VERBATIM, PROC_hammer
prescott, CPU_MODE_VERBATIM, PROC_prescott
conroe, CPU_MODE_VERBATIM, PROC_conroe
penryn, CPU_MODE_VERBATIM, PROC_penryn
nehalem, CPU_MODE_VERBATIM, PROC_nehalem
#
# Features have "no" versions to disable them, and only set/reset the
# specific feature being changed. All other bits are left alone.
#
fpu, CPU_MODE_SET, CPU_FPU
nofpu, CPU_MODE_CLEAR, CPU_FPU
mmx, CPU_MODE_SET, CPU_MMX
nommx, CPU_MODE_CLEAR, CPU_MMX
sse, CPU_MODE_SET, CPU_SSE
nosse, CPU_MODE_CLEAR, CPU_SSE
sse2, CPU_MODE_SET, CPU_SSE2
nosse2, CPU_MODE_CLEAR, CPU_SSE2
sse3, CPU_MODE_SET, CPU_SSE3
nosse3, CPU_MODE_CLEAR, CPU_SSE3
#pni, CPU_MODE_SET, CPU_PNI
#nopni, CPU_MODE_CLEAR, CPU_PNI
3dnow, CPU_MODE_SET, CPU_3DNow
no3dnow, CPU_MODE_CLEAR, CPU_3DNow
cyrix, CPU_MODE_SET, CPU_Cyrix
nocyrix, CPU_MODE_CLEAR, CPU_Cyrix
amd, CPU_MODE_SET, CPU_AMD
noamd, CPU_MODE_CLEAR, CPU_AMD
smm, CPU_MODE_SET, CPU_SMM
nosmm, CPU_MODE_CLEAR, CPU_SMM
prot, CPU_MODE_SET, CPU_Prot
noprot, CPU_MODE_CLEAR, CPU_Prot
protected, CPU_MODE_SET, CPU_Prot
noprotected, CPU_MODE_CLEAR, CPU_Prot
undoc, CPU_MODE_SET, CPU_Undoc
noundoc, CPU_MODE_CLEAR, CPU_Undoc
undocumented, CPU_MODE_SET, CPU_Undoc
noundocumented, CPU_MODE_CLEAR, CPU_Undoc
obs, CPU_MODE_SET, CPU_Obs
noobs, CPU_MODE_CLEAR, CPU_Obs
obsolete, CPU_MODE_SET, CPU_Obs
noobsolete, CPU_MODE_CLEAR, CPU_Obs
priv, CPU_MODE_SET, CPU_Priv
nopriv, CPU_MODE_CLEAR, CPU_Priv
privileged, CPU_MODE_SET, CPU_Priv
noprivileged, CPU_MODE_CLEAR, CPU_Priv
svm, CPU_MODE_SET, CPU_SVM
nosvm, CPU_MODE_CLEAR, CPU_SVM
padlock, CPU_MODE_SET, CPU_PadLock
nopadlock, CPU_MODE_CLEAR, CPU_PadLock
em64t, CPU_MODE_SET, CPU_EM64T
noem64t, CPU_MODE_CLEAR, CPU_EM64T
ssse3, CPU_MODE_SET, CPU_SSSE3
nossse3, CPU_MODE_CLEAR, CPU_SSSE3
sse4.1, CPU_MODE_SET, CPU_SSE41
nosse4.1, CPU_MODE_CLEAR, CPU_SSE41
sse4.2, CPU_MODE_SET, CPU_SSE42
nosse4.2, CPU_MODE_CLEAR, CPU_SSE42
sse4, CPU_MODE_SET, CPU_SSE4
nosse4, CPU_MODE_CLEAR, CPU_SSE4
%%
void
yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid,
size_t cpuid_len)
{
/*@null@*/ const struct cpu_parse_data *pdata;
if (cpuid_len > 15)
return;
pdata = cpu_find(cpuid, cpuid_len);
if (!pdata) {
yasm_warn_set(YASM_WARN_GENERAL,
N_("unrecognized CPU identifier `%s'"), cpuid);
return;
}
switch (pdata->mode) {
case CPU_MODE_VERBATIM:
arch_x86->cpu_enabled = pdata->cpu;
break;
case CPU_MODE_SET:
arch_x86->cpu_enabled |= pdata->cpu;
break;
case CPU_MODE_CLEAR:
arch_x86->cpu_enabled &= ~pdata->cpu;
break;
}
}

@ -0,0 +1,197 @@
/* $Id$
*
* Generate x86 instructions gperf files
*
* Copyright (C) 2006-2007 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
static char line[1024];
static unsigned int cur_line = 1;
unsigned int num_errors = 0;
static void
report_error(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%u: ", cur_line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
num_errors++;
}
static void
parse_insn(FILE *out_nasm, FILE *out_gas)
{
char *parser = strtok(NULL, " \t\n");
char *bname = strtok(NULL, " \t\n");
char *suffix = strtok(NULL, " \t\n");
char *group = strtok(NULL, " \t\n");
char *mod = strtok(NULL, " \t\n");
char *cpu = strtok(NULL, " \t\n");
if (!suffix) {
report_error("INSN requires suffix");
return;
}
if (suffix[0] != '"') {
/* Just one instruction to generate */
if (parser[0] == '-' || strcmp(parser, "gas") == 0)
fprintf(out_gas,
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n",
bname, group, mod, group, cpu, suffix);
if (parser[0] == '-' || strcmp(parser, "nasm") == 0)
fprintf(out_nasm,
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n",
bname, group, mod, group, cpu, suffix);
} else {
/* Need to generate with suffixes for gas */
char *p;
char sufstr[6];
size_t bnamelen = strlen(bname);
char *name = malloc(bnamelen+2);
strcpy(name, bname);
strcpy(sufstr, "SUF_X");
for (p = &suffix[1]; *p != '"'; p++) {
sufstr[4] = toupper(*p);
name[bnamelen] = tolower(*p);
name[bnamelen+1] = '\0';
fprintf(out_gas,
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n",
name, group, mod, group, cpu, sufstr);
}
free(name);
/* And finally the version sans suffix */
if (parser[0] == '-' || strcmp(parser, "gas") == 0)
fprintf(out_gas,
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n",
bname, group, mod, group, cpu, "NONE");
if (parser[0] == '-' || strcmp(parser, "nasm") == 0)
fprintf(out_nasm,
"%s,\t%s_insn,\t(%sUL<<8)|NELEMS(%s_insn),\t%s,\t%s\n",
bname, group, mod, group, cpu, "NONE");
}
}
static void
parse_prefix(FILE *out_nasm, FILE *out_gas)
{
char *parser = strtok(NULL, " \t\n");
char *name = strtok(NULL, " \t\n");
char *type = strtok(NULL, " \t\n");
char *value = strtok(NULL, " \t\n");
if (parser[0] == '-' || strcmp(parser, "gas") == 0)
fprintf(out_gas, "%s,\tNULL,\t%s,\t%s,\tNONE\n", name, type, value);
if (parser[0] == '-' || strcmp(parser, "nasm") == 0)
fprintf(out_nasm, "%s,\tNULL,\t%s,\t%s,\tNONE\n", name, type, value);
}
void
output_base(FILE *out, const char *parser)
{
fputs("%ignore-case\n", out);
fputs("%language=ANSI-C\n", out);
fputs("%compare-strncmp\n", out);
fputs("%readonly-tables\n", out);
fputs("%enum\n", out);
fputs("%struct-type\n", out);
fprintf(out, "%%define hash-function-name insnprefix_%s_hash\n", parser);
fprintf(out, "%%define lookup-function-name insnprefix_%s_find\n", parser);
fputs("struct insnprefix_parse_data;\n", out);
fputs("%%\n", out);
}
int
main(int argc, char *argv[])
{
FILE *in, *out_nasm, *out_gas;
size_t i;
char *tok;
if (argc != 4) {
fprintf(stderr, "Usage: x86geninsn <in> <out_nasm> <out_gas>\n");
return EXIT_FAILURE;
}
in = fopen(argv[1], "rt");
if (!in) {
fprintf(stderr, "Could not open `%s' for reading\n", argv[1]);
return EXIT_FAILURE;
}
out_nasm = fopen(argv[2], "wt");
if (!out_nasm) {
fprintf(stderr, "Could not open `%s' for writing\n", argv[2]);
return EXIT_FAILURE;
}
out_gas = fopen(argv[3], "wt");
if (!out_gas) {
fprintf(stderr, "Could not open `%s' for writing\n", argv[2]);
return EXIT_FAILURE;
}
output_base(out_nasm, "nasm");
output_base(out_gas, "gas");
/* Parse input file */
while (fgets(line, 1024, in)) {
int found;
/*printf("%s\n", line);*/
tok = strtok(line, " \t\n");
if (!tok)
continue;
/* Comments start with # as the first thing on a line */
if (tok[0] == '#')
continue;
if (strcmp(tok, "INSN") == 0)
parse_insn(out_nasm, out_gas);
else if (strcmp(tok, "PREFIX") == 0)
parse_prefix(out_nasm, out_gas);
else
report_error("unknown directive `%s'\n", tok);
cur_line++;
}
if (num_errors > 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}

@ -3417,41 +3417,12 @@ typedef struct insnprefix_parse_data {
WEAK = 0x80 /* Relaxed operand mode for GAS */
} flags;
} insnprefix_parse_data;
#define INSN(name, flags, group, mod, cpu) \
{ name, group##_insn, (mod##UL<<8)|NELEMS(group##_insn), cpu, flags }
#define PREFIX(name, type, value) \
{ name, NULL, type, value, NONE }
/* Static parse data structure for CPU feature flags */
typedef struct cpu_parse_data {
const char *name;
unsigned long cpu;
enum {
CPU_MODE_VERBATIM,
CPU_MODE_SET,
CPU_MODE_CLEAR
} mode;
} cpu_parse_data;
typedef struct regtmod_parse_data {
const char *name;
unsigned long regtmod;
} regtmod_parse_data;
#define REG(name, type, index, bits) \
{ name, (((unsigned long)YASM_ARCH_REG) << 24) | \
(((unsigned long)bits) << 16) | (type | index) }
#define REGGROUP(name, group) \
{ name, (((unsigned long)YASM_ARCH_REGGROUP) << 24) | (group) }
#define SEGREG(name, prefix, num, bits) \
{ name, (((unsigned long)YASM_ARCH_SEGREG) << 24) | \
(((unsigned long)bits) << 16) | (prefix << 8) | (num) }
#define TARGETMOD(name, mod) \
{ name, (((unsigned long)YASM_ARCH_TARGETMOD) << 24) | (mod) }
/* Pull in all parse data */
#include "x86parse.c"
#include "x86insn_nasm.c"
#include "x86insn_gas.c"
static const char *
cpu_find_reverse(unsigned long cpu)
@ -3633,80 +3604,6 @@ yasm_x86__parse_check_insnprefix(yasm_arch *arch, const char *id,
}
}
void
yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid,
size_t cpuid_len)
{
/*@null@*/ const cpu_parse_data *pdata;
size_t i;
static char lcaseid[16];
if (cpuid_len > 15)
return;
for (i=0; i<cpuid_len; i++)
lcaseid[i] = tolower(cpuid[i]);
lcaseid[cpuid_len] = '\0';
pdata = cpu_find(lcaseid, cpuid_len);
if (!pdata) {
yasm_warn_set(YASM_WARN_GENERAL,
N_("unrecognized CPU identifier `%s'"), cpuid);
return;
}
switch (pdata->mode) {
case CPU_MODE_VERBATIM:
arch_x86->cpu_enabled = pdata->cpu;
break;
case CPU_MODE_SET:
arch_x86->cpu_enabled |= pdata->cpu;
break;
case CPU_MODE_CLEAR:
arch_x86->cpu_enabled &= ~pdata->cpu;
break;
}
}
yasm_arch_regtmod
yasm_x86__parse_check_regtmod(yasm_arch *arch, const char *id, size_t id_len,
uintptr_t *data)
{
yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
/*@null@*/ const regtmod_parse_data *pdata;
size_t i;
static char lcaseid[8];
unsigned int bits;
yasm_arch_regtmod type;
if (id_len > 7)
return YASM_ARCH_NOTREGTMOD;
for (i=0; i<id_len; i++)
lcaseid[i] = tolower(id[i]);
lcaseid[id_len] = '\0';
pdata = regtmod_find(lcaseid, id_len);
if (!pdata)
return YASM_ARCH_NOTREGTMOD;
type = (yasm_arch_regtmod)(pdata->regtmod >> 24);
bits = (pdata->regtmod >> 16) & 0xFF;
if (type == YASM_ARCH_REG && bits != 0 && arch_x86->mode_bits != bits) {
yasm_warn_set(YASM_WARN_GENERAL,
N_("`%s' is a register in %u-bit mode"), id, bits);
return YASM_ARCH_NOTREGTMOD;
}
if (type == YASM_ARCH_SEGREG && bits != 0 && arch_x86->mode_bits == bits) {
yasm_warn_set(YASM_WARN_GENERAL,
N_("`%s' segment register ignored in %u-bit mode"), id,
bits);
}
*data = pdata->regtmod & 0x0000FFFFUL;
return type;
}
static void
x86_id_insn_destroy(void *contents)
{

@ -1,4 +1,4 @@
# GAP (gen_arch_parse) input file for x86 architecture
# x86 instruction and prefix recognition
# $Id$
#
# Copyright (C) 2001-2007 Peter Johnson
@ -24,12 +24,6 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Configure GAP for x86 generation mode
ARCH x86
# Supported x86 parsers
PARSERS nasm gas
# INSN parameters:
# - parser (- if any)
# - base name of instruction
@ -910,142 +904,6 @@ INSN - smi NONE onebyte 0x00F1 CPU_386|CPU_Undoc
INSN - umov NONE umov 0 CPU_386|CPU_Undoc
INSN - xbts NONE xbts 0 CPU_386|CPU_Undoc|CPU_Obs
# DEF_CPU parameters:
# - CPU name
# - CPU flags to set
# DEF_CPU_ALIAS parameters:
# - CPU alias name
# - CPU base name
# DEF_CPU_FEATURE parameters:
# - CPU feature name
# - CPU flag to set feature name alone or unset ("no" + feature name)
# The standard CPU names /set/ cpu_enabled.
CPU 8086 CPU_Priv
CPU 186 CPU_186|CPU_Priv
CPU_ALIAS 80186 186
CPU_ALIAS i186 186
CPU 286 CPU_186|CPU_286|CPU_Priv
CPU_ALIAS 80286 286
CPU_ALIAS i286 286
CPU 386 CPU_186|CPU_286|CPU_386|CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS 80386 386
CPU_ALIAS i386 386
CPU 486 CPU_186|CPU_286|CPU_386|CPU_486|CPU_FPU|CPU_SMM|\
CPU_Prot|CPU_Priv
CPU_ALIAS 80486 486
CPU_ALIAS i486 486
CPU 586 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_FPU|\
CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS i586 586
CPU_ALIAS pentium 586
CPU_ALIAS p5 586
CPU 686 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_FPU|CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS i686 686
CPU_ALIAS p6 686
CPU_ALIAS ppro 686
CPU_ALIAS pentiumpro 686
CPU p2 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_FPU|CPU_MMX|CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS pentium2 p2
CPU_ALIAS pentium-2 p2
CPU_ALIAS pentiumii p2
CPU_ALIAS pentium-ii p2
CPU p3 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_P3|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SMM|CPU_Prot|\
CPU_Priv
CPU_ALIAS pentium3 p3
CPU_ALIAS pentium-3 p3
CPU_ALIAS pentiumiii p3
CPU_ALIAS pentium-iii p3
CPU_ALIAS katmai p3
CPU p4 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_P3|CPU_P4|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|\
CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS pentium4 p4
CPU_ALIAS pentium-4 p4
CPU_ALIAS pentiumiv p4
CPU_ALIAS pentium-iv p4
CPU_ALIAS williamette p4
CPU ia64 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_P3|CPU_P4|CPU_IA64|CPU_FPU|CPU_MMX|CPU_SSE|\
CPU_SSE2|CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS ia-64 ia64
CPU_ALIAS itanium ia64
CPU k6 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_K6|CPU_FPU|CPU_MMX|CPU_3DNow|CPU_SMM|CPU_Prot|\
CPU_Priv
CPU k7 CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_K6|CPU_Athlon|CPU_FPU|CPU_MMX|CPU_SSE|CPU_3DNow|\
CPU_SMM|CPU_Prot|CPU_Priv
CPU_ALIAS athlon k7
CPU hammer CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_K6|CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_3DNow|CPU_SMM|CPU_Prot|\
CPU_Priv
CPU_ALIAS sledgehammer hammer
CPU_ALIAS opteron hammer
CPU_ALIAS athlon64 hammer
CPU_ALIAS athlon-64 hammer
CPU prescott CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SMM|\
CPU_Prot|CPU_Priv
CPU conroe CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SMM|\
CPU_Prot|CPU_Priv
CPU penryn CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE41|CPU_SMM|\
CPU_Prot|CPU_Priv
CPU nehalem CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
CPU_Hammer|CPU_EM64T|CPU_FPU|CPU_MMX|\
CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE41|\
CPU_SSE42|CPU_SMM|CPU_Prot|CPU_Priv
# Features have "no" versions to disable them, and only set/reset the
# specific feature being changed. All other bits are left alone.
CPU_FEATURE fpu CPU_FPU
CPU_FEATURE mmx CPU_MMX
CPU_FEATURE sse CPU_SSE
CPU_FEATURE sse2 CPU_SSE2
CPU_FEATURE sse3 CPU_SSE3
#CPU_FEATURE pni CPU_PNI
CPU_FEATURE 3dnow CPU_3DNow
CPU_FEATURE cyrix CPU_Cyrix
CPU_FEATURE amd CPU_AMD
CPU_FEATURE smm CPU_SMM
CPU_FEATURE prot CPU_Prot
CPU_FEATURE protected CPU_Prot
CPU_FEATURE undoc CPU_Undoc
CPU_FEATURE undocumented CPU_Undoc
CPU_FEATURE obs CPU_Obs
CPU_FEATURE obsolete CPU_Obs
CPU_FEATURE priv CPU_Priv
CPU_FEATURE privileged CPU_Priv
CPU_FEATURE svm CPU_SVM
CPU_FEATURE padlock CPU_PadLock
CPU_FEATURE em64t CPU_EM64T
CPU_FEATURE ssse3 CPU_SSSE3
CPU_FEATURE sse4.1 CPU_SSE41
CPU_FEATURE sse4.2 CPU_SSE42
CPU_FEATURE sse4 CPU_SSE4
# TARGETMOD parameters:
# - target modifier name
# - modifier to return
TARGETMOD near X86_NEAR
TARGETMOD short X86_SHORT
TARGETMOD far X86_FAR
TARGETMOD to X86_TO
# PREFIX parameters:
# - parser
# - prefix name
@ -1105,170 +963,3 @@ PREFIX gas rex64xz X86_REX 0x4D
PREFIX gas rex64xy X86_REX 0x4E
PREFIX gas rex64xyz X86_REX 0x4F
# REG parameters:
# - register name
# - register type
# - register index
# - required BITS setting (0 for any)
#
# REGGROUP parameters:
# - register group name
# - register group type
#
# SEGREG parameters:
# - segment register name
# - prefix encoding
# - register encoding
# - BITS in which the segment is ignored
# control, debug, and test registers
REG cr0 X86_CRREG 0 0
REG cr2 X86_CRREG 2 0
REG cr3 X86_CRREG 3 0
REG cr4 X86_CRREG 4 0
REG cr8 X86_CRREG 8 64
REG dr0 X86_DRREG 0 0
REG dr1 X86_DRREG 1 0
REG dr2 X86_DRREG 2 0
REG dr3 X86_DRREG 3 0
REG dr4 X86_DRREG 4 0
REG dr5 X86_DRREG 5 0
REG dr6 X86_DRREG 6 0
REG dr7 X86_DRREG 7 0
REG tr0 X86_TRREG 0 0
REG tr1 X86_TRREG 1 0
REG tr2 X86_TRREG 2 0
REG tr3 X86_TRREG 3 0
REG tr4 X86_TRREG 4 0
REG tr5 X86_TRREG 5 0
REG tr6 X86_TRREG 6 0
REG tr7 X86_TRREG 7 0
# floating point, MMX, and SSE/SSE2 registers
REG st0 X86_FPUREG 0 0
REG st1 X86_FPUREG 1 0
REG st2 X86_FPUREG 2 0
REG st3 X86_FPUREG 3 0
REG st4 X86_FPUREG 4 0
REG st5 X86_FPUREG 5 0
REG st6 X86_FPUREG 6 0
REG st7 X86_FPUREG 7 0
REG mm0 X86_MMXREG 0 0
REG mm1 X86_MMXREG 1 0
REG mm2 X86_MMXREG 2 0
REG mm3 X86_MMXREG 3 0
REG mm4 X86_MMXREG 4 0
REG mm5 X86_MMXREG 5 0
REG mm6 X86_MMXREG 6 0
REG mm7 X86_MMXREG 7 0
REG xmm0 X86_XMMREG 0 0
REG xmm1 X86_XMMREG 1 0
REG xmm2 X86_XMMREG 2 0
REG xmm3 X86_XMMREG 3 0
REG xmm4 X86_XMMREG 4 0
REG xmm5 X86_XMMREG 5 0
REG xmm6 X86_XMMREG 6 0
REG xmm7 X86_XMMREG 7 0
REG xmm8 X86_XMMREG 8 64
REG xmm9 X86_XMMREG 9 64
REG xmm10 X86_XMMREG 10 64
REG xmm11 X86_XMMREG 11 64
REG xmm12 X86_XMMREG 12 64
REG xmm13 X86_XMMREG 13 64
REG xmm14 X86_XMMREG 14 64
REG xmm15 X86_XMMREG 15 64
# integer registers
REG rax X86_REG64 0 64
REG rcx X86_REG64 1 64
REG rdx X86_REG64 2 64
REG rbx X86_REG64 3 64
REG rsp X86_REG64 4 64
REG rbp X86_REG64 5 64
REG rsi X86_REG64 6 64
REG rdi X86_REG64 7 64
REG r8 X86_REG64 8 64
REG r9 X86_REG64 9 64
REG r10 X86_REG64 10 64
REG r11 X86_REG64 11 64
REG r12 X86_REG64 12 64
REG r13 X86_REG64 13 64
REG r14 X86_REG64 14 64
REG r15 X86_REG64 15 64
REG eax X86_REG32 0 0
REG ecx X86_REG32 1 0
REG edx X86_REG32 2 0
REG ebx X86_REG32 3 0
REG esp X86_REG32 4 0
REG ebp X86_REG32 5 0
REG esi X86_REG32 6 0
REG edi X86_REG32 7 0
REG r8d X86_REG32 8 64
REG r9d X86_REG32 9 64
REG r10d X86_REG32 10 64
REG r11d X86_REG32 11 64
REG r12d X86_REG32 12 64
REG r13d X86_REG32 13 64
REG r14d X86_REG32 14 64
REG r15d X86_REG32 15 64
REG ax X86_REG16 0 0
REG cx X86_REG16 1 0
REG dx X86_REG16 2 0
REG bx X86_REG16 3 0
REG sp X86_REG16 4 0
REG bp X86_REG16 5 0
REG si X86_REG16 6 0
REG di X86_REG16 7 0
REG r8w X86_REG16 8 64
REG r9w X86_REG16 9 64
REG r10w X86_REG16 10 64
REG r11w X86_REG16 11 64
REG r12w X86_REG16 12 64
REG r13w X86_REG16 13 64
REG r14w X86_REG16 14 64
REG r15w X86_REG16 15 64
REG al X86_REG8 0 0
REG cl X86_REG8 1 0
REG dl X86_REG8 2 0
REG bl X86_REG8 3 0
REG ah X86_REG8 4 0
REG ch X86_REG8 5 0
REG dh X86_REG8 6 0
REG bh X86_REG8 7 0
REG r8b X86_REG8 8 64
REG r9b X86_REG8 9 64
REG r10b X86_REG8 10 64
REG r11b X86_REG8 11 64
REG r12b X86_REG8 12 64
REG r13b X86_REG8 13 64
REG r14b X86_REG8 14 64
REG r15b X86_REG8 15 64
REG spl X86_REG8X 4 64
REG bpl X86_REG8X 5 64
REG sil X86_REG8X 6 64
REG dil X86_REG8X 7 64
REG rip X86_RIP 0 64
# floating point, MMX, and SSE/SSE2 registers
REGGROUP st X86_FPUREG
REGGROUP mm X86_MMXREG
REGGROUP xmm X86_XMMREG
# segment registers
SEGREG es 0x26 0x00 64
SEGREG cs 0x2e 0x01 0
SEGREG ss 0x36 0x02 64
SEGREG ds 0x3e 0x03 64
SEGREG fs 0x64 0x04 0
SEGREG gs 0x65 0x05 0

@ -0,0 +1,274 @@
#
# x86 register and target modifier recognition
#
# Copyright (C) 2002-2007 Peter Johnson
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
%{
#include <util.h>
RCSID("$Id$");
#include <libyasm.h>
#include <libyasm/phash.h>
#include "modules/arch/x86/x86arch.h"
enum regtmod_type {
REG = 1,
REGGROUP,
SEGREG,
TARGETMOD
};
%}
%ignore-case
%language=ANSI-C
%compare-strncmp
%readonly-tables
%enum
%struct-type
%define hash-function-name regtmod_hash
%define lookup-function-name regtmod_find
struct regtmod_parse_data {
const char *name;
unsigned int type:8; /* regtmod_type */
/* REG: register size
* SEGREG: prefix encoding
* Others: 0
*/
unsigned int size_prefix:8;
/* REG: register index
* REGGROUP: register group type
* SEGREG: register encoding
* TARGETMOD: target modifier
*/
unsigned int data:8;
/* REG: required bits setting
* SEGREG: BITS in which the segment is ignored
* Others: 0
*/
unsigned int bits:8;
};
%%
#
# control, debug, and test registers
#
cr0, REG, X86_CRREG, 0, 0
cr2, REG, X86_CRREG, 2, 0
cr3, REG, X86_CRREG, 3, 0
cr4, REG, X86_CRREG, 4, 0
cr8, REG, X86_CRREG, 8, 64
#
dr0, REG, X86_DRREG, 0, 0
dr1, REG, X86_DRREG, 1, 0
dr2, REG, X86_DRREG, 2, 0
dr3, REG, X86_DRREG, 3, 0
dr4, REG, X86_DRREG, 4, 0
dr5, REG, X86_DRREG, 5, 0
dr6, REG, X86_DRREG, 6, 0
dr7, REG, X86_DRREG, 7, 0
#
tr0, REG, X86_TRREG, 0, 0
tr1, REG, X86_TRREG, 1, 0
tr2, REG, X86_TRREG, 2, 0
tr3, REG, X86_TRREG, 3, 0
tr4, REG, X86_TRREG, 4, 0
tr5, REG, X86_TRREG, 5, 0
tr6, REG, X86_TRREG, 6, 0
tr7, REG, X86_TRREG, 7, 0
#
# floating point, MMX, and SSE/SSE2 registers
#
st0, REG, X86_FPUREG, 0, 0
st1, REG, X86_FPUREG, 1, 0
st2, REG, X86_FPUREG, 2, 0
st3, REG, X86_FPUREG, 3, 0
st4, REG, X86_FPUREG, 4, 0
st5, REG, X86_FPUREG, 5, 0
st6, REG, X86_FPUREG, 6, 0
st7, REG, X86_FPUREG, 7, 0
#
mm0, REG, X86_MMXREG, 0, 0
mm1, REG, X86_MMXREG, 1, 0
mm2, REG, X86_MMXREG, 2, 0
mm3, REG, X86_MMXREG, 3, 0
mm4, REG, X86_MMXREG, 4, 0
mm5, REG, X86_MMXREG, 5, 0
mm6, REG, X86_MMXREG, 6, 0
mm7, REG, X86_MMXREG, 7, 0
#
xmm0, REG, X86_XMMREG, 0, 0
xmm1, REG, X86_XMMREG, 1, 0
xmm2, REG, X86_XMMREG, 2, 0
xmm3, REG, X86_XMMREG, 3, 0
xmm4, REG, X86_XMMREG, 4, 0
xmm5, REG, X86_XMMREG, 5, 0
xmm6, REG, X86_XMMREG, 6, 0
xmm7, REG, X86_XMMREG, 7, 0
xmm8, REG, X86_XMMREG, 8, 64
xmm9, REG, X86_XMMREG, 9, 64
xmm10, REG, X86_XMMREG, 10, 64
xmm11, REG, X86_XMMREG, 11, 64
xmm12, REG, X86_XMMREG, 12, 64
xmm13, REG, X86_XMMREG, 13, 64
xmm14, REG, X86_XMMREG, 14, 64
xmm15, REG, X86_XMMREG, 15, 64
#
# integer registers
#
rax, REG, X86_REG64, 0, 64
rcx, REG, X86_REG64, 1, 64
rdx, REG, X86_REG64, 2, 64
rbx, REG, X86_REG64, 3, 64
rsp, REG, X86_REG64, 4, 64
rbp, REG, X86_REG64, 5, 64
rsi, REG, X86_REG64, 6, 64
rdi, REG, X86_REG64, 7, 64
r8, REG, X86_REG64, 8, 64
r9, REG, X86_REG64, 9, 64
r10, REG, X86_REG64, 10, 64
r11, REG, X86_REG64, 11, 64
r12, REG, X86_REG64, 12, 64
r13, REG, X86_REG64, 13, 64
r14, REG, X86_REG64, 14, 64
r15, REG, X86_REG64, 15, 64
#
eax, REG, X86_REG32, 0, 0
ecx, REG, X86_REG32, 1, 0
edx, REG, X86_REG32, 2, 0
ebx, REG, X86_REG32, 3, 0
esp, REG, X86_REG32, 4, 0
ebp, REG, X86_REG32, 5, 0
esi, REG, X86_REG32, 6, 0
edi, REG, X86_REG32, 7, 0
r8d, REG, X86_REG32, 8, 64
r9d, REG, X86_REG32, 9, 64
r10d, REG, X86_REG32, 10, 64
r11d, REG, X86_REG32, 11, 64
r12d, REG, X86_REG32, 12, 64
r13d, REG, X86_REG32, 13, 64
r14d, REG, X86_REG32, 14, 64
r15d, REG, X86_REG32, 15, 64
#
ax, REG, X86_REG16, 0, 0
cx, REG, X86_REG16, 1, 0
dx, REG, X86_REG16, 2, 0
bx, REG, X86_REG16, 3, 0
sp, REG, X86_REG16, 4, 0
bp, REG, X86_REG16, 5, 0
si, REG, X86_REG16, 6, 0
di, REG, X86_REG16, 7, 0
r8w, REG, X86_REG16, 8, 64
r9w, REG, X86_REG16, 9, 64
r10w, REG, X86_REG16, 10, 64
r11w, REG, X86_REG16, 11, 64
r12w, REG, X86_REG16, 12, 64
r13w, REG, X86_REG16, 13, 64
r14w, REG, X86_REG16, 14, 64
r15w, REG, X86_REG16, 15, 64
#
al, REG, X86_REG8, 0, 0
cl, REG, X86_REG8, 1, 0
dl, REG, X86_REG8, 2, 0
bl, REG, X86_REG8, 3, 0
ah, REG, X86_REG8, 4, 0
ch, REG, X86_REG8, 5, 0
dh, REG, X86_REG8, 6, 0
bh, REG, X86_REG8, 7, 0
r8b, REG, X86_REG8, 8, 64
r9b, REG, X86_REG8, 9, 64
r10b, REG, X86_REG8, 10, 64
r11b, REG, X86_REG8, 11, 64
r12b, REG, X86_REG8, 12, 64
r13b, REG, X86_REG8, 13, 64
r14b, REG, X86_REG8, 14, 64
r15b, REG, X86_REG8, 15, 64
#
spl, REG, X86_REG8X, 4, 64
bpl, REG, X86_REG8X, 5, 64
sil, REG, X86_REG8X, 6, 64
dil, REG, X86_REG8X, 7, 64
#
rip, REG, X86_RIP, 0, 64
#
# floating point, MMX, and SSE/SSE2 registers
#
st, REGGROUP, 0, X86_FPUREG, 0
mm, REGGROUP, 0, X86_MMXREG, 0
xmm, REGGROUP, 0, X86_XMMREG, 0
#
# segment registers
#
es, SEGREG, 0x26, 0x00, 64
cs, SEGREG, 0x2e, 0x01, 0
ss, SEGREG, 0x36, 0x02, 64
ds, SEGREG, 0x3e, 0x03, 64
fs, SEGREG, 0x64, 0x04, 0
gs, SEGREG, 0x65, 0x05, 0
#
# target modifiers
#
near, TARGETMOD, 0, X86_NEAR, 0
short, TARGETMOD, 0, X86_SHORT, 0
far, TARGETMOD, 0, X86_FAR, 0
to, TARGETMOD, 0, X86_TO, 0
%%
yasm_arch_regtmod
yasm_x86__parse_check_regtmod(yasm_arch *arch, const char *id, size_t id_len,
uintptr_t *data)
{
yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
/*@null@*/ const struct regtmod_parse_data *pdata;
unsigned int bits;
yasm_arch_regtmod type;
if (id_len > 7)
return YASM_ARCH_NOTREGTMOD;
pdata = regtmod_find(id, id_len);
if (!pdata)
return YASM_ARCH_NOTREGTMOD;
type = (yasm_arch_regtmod)pdata->type;
bits = pdata->bits;
if (type == YASM_ARCH_REG && bits != 0 && arch_x86->mode_bits != bits) {
yasm_warn_set(YASM_WARN_GENERAL,
N_("`%s' is a register in %u-bit mode"), id, bits);
return YASM_ARCH_NOTREGTMOD;
}
if (type == YASM_ARCH_SEGREG && bits != 0 && arch_x86->mode_bits == bits) {
yasm_warn_set(YASM_WARN_GENERAL,
N_("`%s' segment register ignored in %u-bit mode"), id,
bits);
}
if (type == YASM_ARCH_SEGREG)
*data = (pdata->size_prefix<<8) | pdata->data;
else
*data = pdata->size_prefix | pdata->data;
return type;
}

@ -1,9 +1,9 @@
# $Id$
EXTRA_DIST += tools/re2c/Makefile.inc
EXTRA_DIST += tools/gap/Makefile.inc
EXTRA_DIST += tools/genperf/Makefile.inc
EXTRA_DIST += tools/python-yasm/Makefile.inc
include tools/re2c/Makefile.inc
include tools/gap/Makefile.inc
include tools/genperf/Makefile.inc
include tools/python-yasm/Makefile.inc

@ -1,34 +0,0 @@
# $Id$
# These utility programs have to be built for BUILD host in cross-build.
# This makes things rather non-standard automake
noinst_PROGRAMS += gap
gap_SOURCES =
EXTRA_DIST += tools/gap/gap.c
EXTRA_DIST += tools/gap/perfect.c
EXTRA_DIST += tools/gap/perfect.h
EXTRA_DIST += tools/gap/standard.h
gap_LDADD = gap.$(OBJEXT)
gap_LDADD += gap-perfect.$(OBJEXT)
gap_LDADD += gap-phash.$(OBJEXT)
gap_LDADD += gap-xmalloc.$(OBJEXT)
gap_LDADD += gap-xstrdup.$(OBJEXT)
gap_LINK = $(CCLD_FOR_BUILD) -o $@
gap.$(OBJEXT): tools/gap/gap.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/gap/gap.c || echo '$(srcdir)/'`tools/gap/gap.c
gap-perfect.$(OBJEXT): tools/gap/perfect.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/gap/perfect.c || echo '$(srcdir)/'`tools/gap/perfect.c
gap-phash.$(OBJEXT): libyasm/phash.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/phash.c || echo '$(srcdir)/'`libyasm/phash.c
gap-xmalloc.$(OBJEXT): libyasm/xmalloc.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xmalloc.c || echo '$(srcdir)/'`libyasm/xmalloc.c
gap-xstrdup.$(OBJEXT): libyasm/xstrdup.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xstrdup.c || echo '$(srcdir)/'`libyasm/xstrdup.c

@ -1,854 +0,0 @@
/* $Id$
*
* Generate Arch Parser (GAP): generates ARCHparse.c from ARCHparse.gap.
*
* Copyright (C) 2006-2007 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include "tools/gap/perfect.h"
#include "libyasm/compat-queue.h"
#include "libyasm/coretype.h"
#include "libyasm/errwarn.h"
typedef STAILQ_HEAD(slist, sval) slist;
typedef struct sval {
STAILQ_ENTRY(sval) link;
char *str;
} sval;
typedef STAILQ_HEAD(dir_list, dir) dir_list;
typedef struct dir {
STAILQ_ENTRY(dir) link;
char *name;
const char *func;
slist args;
} dir;
typedef STAILQ_HEAD(dir_byp_list, dir_byp) dir_byp_list;
typedef struct dir_byp {
STAILQ_ENTRY(dir_byp) link;
/*@null@*/ char *parser;
dir_list dirs;
} dir_byp;
typedef enum {
ARCH = 0,
PARSERS,
INSN,
CPU,
CPU_ALIAS,
CPU_FEATURE,
TARGETMOD,
PREFIX,
REG,
REGGROUP,
SEGREG,
NUM_DIRS
} dir_type;
typedef struct {
void (*parse_insn) (void); /* arch-specific parse_insn */
int multi_parser[NUM_DIRS]; /* whether it has an initial parser field */
} arch_handler;
static void x86_parse_insn(void);
static const arch_handler arch_x86 = {
x86_parse_insn,
{0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0}
};
static struct {
const char *name;
const arch_handler *arch;
} archs[] = {
{"x86", &arch_x86},
};
static char line[1024];
static unsigned int cur_line = 0, next_line = 1;
static int errors = 0;
static const arch_handler *arch = NULL;
/* Lists of directives, keyed by parser name */
static dir_byp_list insnprefix_byp;
static dir_byp_list cpu_byp;
static dir_byp_list regtmod_byp;
static void
report_error(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%u: ", cur_line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
errors++;
}
void
yasm__fatal(const char *message, ...)
{
abort();
}
static void
dup_slist(slist *out, slist *in)
{
sval *sv;
STAILQ_INIT(out);
STAILQ_FOREACH(sv, in, link) {
sval *nsv = yasm_xmalloc(sizeof(sval));
nsv->str = yasm__xstrdup(sv->str);
STAILQ_INSERT_TAIL(out, nsv, link);
}
}
static dir *
dup_dir(dir *in)
{
dir *out = yasm_xmalloc(sizeof(dir));
out->name = yasm__xstrdup(in->name);
out->func = in->func;
dup_slist(&out->args, &in->args);
return out;
}
static dir_list *
get_dirs(dir_byp_list *byp, /*@null@*/ const char *parser)
{
dir_list *found = NULL;
dir_byp *db;
if (STAILQ_EMPTY(byp)) {
report_error("PARSERS not yet specified");
return NULL;
}
STAILQ_FOREACH(db, byp, link) {
if ((!parser && !db->parser) ||
(parser && db->parser && strcmp(parser, db->parser) == 0)) {
found = &db->dirs;
break;
}
}
return found;
}
/* Add a keyword/data to a slist of slist keyed by parser name.
* Returns nonzero on error.
*/
static int
add_dir(dir_byp_list *byp, /*@null@*/ const char *parser, dir *d)
{
dir_list *found = get_dirs(byp, parser);
if (found) {
STAILQ_INSERT_TAIL(found, d, link);
return 0;
} else if (!parser) {
/* Add separately to all */
dir_byp *db;
int first = 1;
STAILQ_FOREACH(db, byp, link) {
if (!first)
d = dup_dir(d);
first = 0;
STAILQ_INSERT_TAIL(&db->dirs, d, link);
}
return 0;
} else {
report_error("parser not found");
return 1;
}
}
static char *
check_parser(dir_type type)
{
char *parser = NULL;
if (arch->multi_parser[type]) {
parser = strtok(NULL, " \t\n");
if (strcmp(parser, "-") == 0)
parser = NULL;
}
return parser;
}
static void
parse_args(slist *args)
{
char *tok;
sval *sv;
STAILQ_INIT(args);
tok = strtok(NULL, " \t\n");
if (!tok) {
report_error("no args");
return;
}
while (tok) {
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(tok);
STAILQ_INSERT_TAIL(args, sv, link);
tok = strtok(NULL, " \t\n");
}
}
static dir *
parse_generic(dir_type type, const char *func, dir_byp_list *byp)
{
char *parser = check_parser(type);
char *name = strtok(NULL, " \t\n");
dir *d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(name);
d->func = func;
parse_args(&d->args);
add_dir(byp, parser, d);
return d;
}
static void
parse_arch(void)
{
size_t i;
int found = 0;
char *tok = strtok(NULL, " \t\n");
if (!tok) {
report_error("ARCH requires an operand");
return;
}
for (i=0; i<sizeof(archs)/sizeof(archs[0]); i++) {
if (strcmp(archs[i].name, tok) == 0) {
found = 1;
break;
}
}
if (!found) {
report_error("unrecognized ARCH");
return;
}
arch = archs[i].arch;
}
static void
parse_parsers(void)
{
dir_byp *db;
char *tok;
if (!arch) {
report_error("ARCH not specified before PARSERS");
return;
}
tok = strtok(NULL, " \t\n");
if (!tok) {
report_error("no PARSERS parameter");
return;
}
while (tok) {
/* Insert into each slist of slist if broken out by parser */
if (arch->multi_parser[INSN] || arch->multi_parser[PREFIX]) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = yasm__xstrdup(tok);
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&insnprefix_byp, db, link);
}
if (arch->multi_parser[CPU] || arch->multi_parser[CPU_ALIAS] ||
arch->multi_parser[CPU_FEATURE]) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = yasm__xstrdup(tok);
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&cpu_byp, db, link);
}
if (arch->multi_parser[TARGETMOD] || arch->multi_parser[REG] ||
arch->multi_parser[REGGROUP] || arch->multi_parser[SEGREG]) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = yasm__xstrdup(tok);
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&regtmod_byp, db, link);
}
tok = strtok(NULL, " \t\n");
}
/* Add NULL (global) versions if not already created */
if (STAILQ_EMPTY(&insnprefix_byp)) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = NULL;
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&insnprefix_byp, db, link);
}
if (STAILQ_EMPTY(&cpu_byp)) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = NULL;
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&cpu_byp, db, link);
}
if (STAILQ_EMPTY(&regtmod_byp)) {
db = yasm_xmalloc(sizeof(dir_byp));
db->parser = NULL;
STAILQ_INIT(&db->dirs);
STAILQ_INSERT_TAIL(&regtmod_byp, db, link);
}
}
static void
x86_parse_insn(void)
{
char *parser = check_parser(INSN);
char *bname = strtok(NULL, " \t\n");
char *suffix = strtok(NULL, " \t\n");
dir *d;
slist args;
sval *sv;
if (!suffix) {
report_error("INSN requires suffix");
return;
}
/* save the remainder of args */
parse_args(&args);
if (suffix[0] != '"') {
/* Just one instruction to generate */
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(suffix);
STAILQ_INSERT_HEAD(&args, sv, link);
d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(bname);
d->func = "INSN";
d->args = args;
add_dir(&insnprefix_byp, parser, d);
} else {
/* Need to generate with suffixes for gas */
char *p;
char sufstr[6];
size_t bnamelen = strlen(bname);
strcpy(sufstr, "SUF_X");
for (p = &suffix[1]; *p != '"'; p++) {
sufstr[4] = toupper(*p);
d = yasm_xmalloc(sizeof(dir));
d->name = yasm_xmalloc(bnamelen+2);
strcpy(d->name, bname);
d->name[bnamelen] = tolower(*p);
d->name[bnamelen+1] = '\0';
d->func = "INSN";
dup_slist(&d->args, &args);
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(sufstr);
STAILQ_INSERT_HEAD(&d->args, sv, link);
add_dir(&insnprefix_byp, "gas", d);
}
/* And finally the version sans suffix */
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("NONE");
STAILQ_INSERT_HEAD(&args, sv, link);
d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(bname);
d->func = "INSN";
d->args = args;
add_dir(&insnprefix_byp, parser, d);
}
}
static void
parse_insn(void)
{
if (!arch) {
report_error("ARCH not defined prior to INSN");
return;
}
arch->parse_insn();
}
static void
parse_cpu(void)
{
dir *d = parse_generic(CPU, "CPU", &cpu_byp);
sval *sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("CPU_MODE_VERBATIM");
STAILQ_INSERT_TAIL(&d->args, sv, link);
}
static void
parse_cpu_alias(void)
{
char *parser = check_parser(CPU_ALIAS);
char *name = strtok(NULL, " \t\n");
char *alias = strtok(NULL, " \t\n");
dir_list *dirs = get_dirs(&cpu_byp, parser);
dir *aliasd, *d;
if (!alias) {
report_error("CPU_ALIAS requires an operand");
return;
}
STAILQ_FOREACH(aliasd, dirs, link) {
if (strcmp(aliasd->name, alias) == 0)
break;
}
if (!aliasd) {
report_error("could not find `%s'", alias);
return;
}
d = yasm_xmalloc(sizeof(dir));
d->name = yasm__xstrdup(name);
d->func = "CPU";
dup_slist(&d->args, &aliasd->args);
add_dir(&cpu_byp, parser, d);
}
static void
parse_cpu_feature(void)
{
char *parser = check_parser(CPU_FEATURE);
char *name = strtok(NULL, " \t\n");
dir *name_dir = yasm_xmalloc(sizeof(dir));
dir *noname_dir = yasm_xmalloc(sizeof(dir));
sval *sv;
name_dir->name = yasm__xstrdup(name);
name_dir->func = "CPU_FEATURE";
parse_args(&name_dir->args);
noname_dir->name = yasm_xmalloc(strlen(name)+3);
strcpy(noname_dir->name, "no");
strcat(noname_dir->name, name);
noname_dir->func = name_dir->func;
dup_slist(&noname_dir->args, &name_dir->args);
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("CPU_MODE_SET");
STAILQ_INSERT_TAIL(&name_dir->args, sv, link);
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup("CPU_MODE_CLEAR");
STAILQ_INSERT_TAIL(&noname_dir->args, sv, link);
add_dir(&cpu_byp, parser, name_dir);
add_dir(&cpu_byp, parser, noname_dir);
}
static void
parse_targetmod(void)
{
parse_generic(TARGETMOD, "TARGETMOD", &regtmod_byp);
}
static void
parse_prefix(void)
{
parse_generic(PREFIX, "PREFIX", &insnprefix_byp);
}
static void
parse_reg(void)
{
parse_generic(REG, "REG", &regtmod_byp);
}
static void
parse_reggroup(void)
{
parse_generic(REGGROUP, "REGGROUP", &regtmod_byp);
}
static void
parse_segreg(void)
{
parse_generic(SEGREG, "SEGREG", &regtmod_byp);
}
/* make the c output for the perfect hash tab array */
static void
make_c_tab(
FILE *f,
const char *which,
const char *parser,
bstuff *tab, /* table indexed by b */
ub4 smax, /* range of scramble[] */
ub4 blen, /* b in 0..blen-1, power of 2 */
ub4 *scramble) /* used in final hash */
{
ub4 i;
/* table for the mapping for the perfect hash */
if (blen >= USE_SCRAMBLE) {
/* A way to make the 1-byte values in tab bigger */
if (smax > UB2MAXVAL+1) {
fprintf(f, "static const unsigned long %s_", which);
if (parser)
fprintf(f, "%s_", parser);
fprintf(f, "scramble[] = {\n");
for (i=0; i<=UB1MAXVAL; i+=4)
fprintf(f, "0x%.8lx, 0x%.8lx, 0x%.8lx, 0x%.8lx,\n",
scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3]);
} else {
fprintf(f, "static const unsigned short %s_", which);
if (parser)
fprintf(f, "%s_", parser);
fprintf(f, "scramble[] = {\n");
for (i=0; i<=UB1MAXVAL; i+=8)
fprintf(f,
"0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx,\n",
scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3],
scramble[i+4], scramble[i+5], scramble[i+6], scramble[i+7]);
}
fprintf(f, "};\n");
fprintf(f, "\n");
}
if (blen > 0) {
/* small adjustments to _a_ to make values distinct */
if (smax <= UB1MAXVAL+1 || blen >= USE_SCRAMBLE)
fprintf(f, "static const unsigned char %s_", which);
else
fprintf(f, "static const unsigned short %s_", which);
if (parser)
fprintf(f, "%s_", parser);
fprintf(f, "tab[] = {\n");
if (blen < 16) {
for (i=0; i<blen; ++i)
fprintf(f, "%3ld,", scramble[tab[i].val_b]);
} else if (blen <= 1024) {
for (i=0; i<blen; i+=16)
fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
scramble[tab[i+0].val_b], scramble[tab[i+1].val_b],
scramble[tab[i+2].val_b], scramble[tab[i+3].val_b],
scramble[tab[i+4].val_b], scramble[tab[i+5].val_b],
scramble[tab[i+6].val_b], scramble[tab[i+7].val_b],
scramble[tab[i+8].val_b], scramble[tab[i+9].val_b],
scramble[tab[i+10].val_b], scramble[tab[i+11].val_b],
scramble[tab[i+12].val_b], scramble[tab[i+13].val_b],
scramble[tab[i+14].val_b], scramble[tab[i+15].val_b]);
} else if (blen < USE_SCRAMBLE) {
for (i=0; i<blen; i+=8)
fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
scramble[tab[i+0].val_b], scramble[tab[i+1].val_b],
scramble[tab[i+2].val_b], scramble[tab[i+3].val_b],
scramble[tab[i+4].val_b], scramble[tab[i+5].val_b],
scramble[tab[i+6].val_b], scramble[tab[i+7].val_b]);
} else {
for (i=0; i<blen; i+=16)
fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\n",
tab[i+0].val_b, tab[i+1].val_b,
tab[i+2].val_b, tab[i+3].val_b,
tab[i+4].val_b, tab[i+5].val_b,
tab[i+6].val_b, tab[i+7].val_b,
tab[i+8].val_b, tab[i+9].val_b,
tab[i+10].val_b, tab[i+11].val_b,
tab[i+12].val_b, tab[i+13].val_b,
tab[i+14].val_b, tab[i+15].val_b);
}
fprintf(f, "};\n");
fprintf(f, "\n");
}
}
static void
perfect_dir(FILE *out, const char *which, const char *parser, dir_list *dirs)
{
ub4 nkeys;
key *keys;
hashform form;
bstuff *tab; /* table indexed by b */
hstuff *tabh; /* table indexed by hash value */
ub4 smax; /* scramble[] values in 0..smax-1, a power of 2 */
ub4 alen; /* a in 0..alen-1, a power of 2 */
ub4 blen; /* b in 0..blen-1, a power of 2 */
ub4 salt; /* a parameter to the hash function */
gencode final; /* code for final hash */
ub4 i;
ub4 scramble[SCRAMBLE_LEN]; /* used in final hash function */
char buf[10][80]; /* buffer for generated code */
char *buf2[10]; /* also for generated code */
int cpumode = strcmp(which, "cpu") == 0;
dir *d;
/* perfect hash configuration */
form.mode = NORMAL_HM;
form.hashtype = STRING_HT;
form.perfect = MINIMAL_HP;
form.speed = SLOW_HS;
/* set up code for final hash */
final.line = buf2;
final.used = 0;
final.len = 10;
for (i=0; i<10; i++)
final.line[i] = buf[i];
/* build list of keys */
nkeys = 0;
keys = NULL;
STAILQ_FOREACH(d, dirs, link) {
key *k = yasm_xmalloc(sizeof(key));
k->name_k = yasm__xstrdup(d->name);
k->len_k = (ub4)strlen(d->name);
k->next_k = keys;
keys = k;
nkeys++;
}
/* find the hash */
findhash(&tab, &tabh, &alen, &blen, &salt, &final,
scramble, &smax, keys, nkeys, &form);
/* output the dir table: this should loop up to smax for NORMAL_HP,
* or up to pakd.nkeys for MINIMAL_HP.
*/
fprintf(out, "static const %s_parse_data %s_", which, which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "pd[%lu] = {\n", nkeys);
for (i=0; i<nkeys; i++) {
if (tabh[i].key_h) {
sval *sv;
STAILQ_FOREACH(d, dirs, link) {
if (strcmp(d->name, tabh[i].key_h->name_k) == 0)
break;
}
if (!d) {
report_error("internal error: could not find `%s'",
tabh[i].key_h->name_k);
break;
}
if (cpumode)
fprintf(out, "{\"%s\",", d->name);
else
fprintf(out, "%s(\"%s\",", d->func, d->name);
STAILQ_FOREACH(sv, &d->args, link) {
fprintf(out, " %s", sv->str);
if (STAILQ_NEXT(sv, link))
fprintf(out, ",");
}
fprintf(out, cpumode ? "}" : ")");
} else
fprintf(out, " { NULL }");
if (i < nkeys-1)
fprintf(out, ",");
fprintf(out, "\n");
}
fprintf(out, "};\n");
/* output the hash tab[] array */
make_c_tab(out, which, parser, tab, smax, blen, scramble);
/* The hash function */
fprintf(out, "#define tab %s_", which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "tab\n");
fprintf(out, "static const %s_parse_data *\n%s_", which, which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "find(const char *key, size_t len)\n");
fprintf(out, "{\n");
fprintf(out, " const %s_parse_data *ret;\n", which);
for (i=0; i<final.used; ++i)
fprintf(out, final.line[i]);
fprintf(out, " if (rsl >= %lu) return NULL;\n", nkeys);
fprintf(out, " ret = &%s_", which);
if (parser)
fprintf(out, "%s_", parser);
fprintf(out, "pd[rsl];\n");
fprintf(out, " if (strcmp(key, ret->name) != 0) return NULL;\n");
fprintf(out, " return ret;\n");
fprintf(out, "}\n");
fprintf(out, "#undef tab\n\n");
free(tab);
free(tabh);
}
/* Get an entire "real" line from the input file by combining any
* \\\n continuations.
*/
static int get_line(FILE *in)
{
char *p = line;
cur_line = next_line;
if (feof(in))
return 0;
while (p < &line[1023-128]) {
if (!fgets(p, 128, in))
return 1;
next_line++;
/* if continuation, strip out leading whitespace */
if (p > line) {
char *p2 = p;
while (isspace(*p2)) p2++;
if (p2 > p)
memmove(p, p2, strlen(p2)+1);
}
while (*p) p++;
if (p[-2] != '\\' || p[-1] != '\n') {
if (p[-1] == '\n')
p[-1] = '\0';
return 1;
}
p -= 2;
}
return 0;
}
static struct {
const char *name;
int indx;
void (*handler) (void);
} directives[] = {
{"ARCH", ARCH, parse_arch},
{"PARSERS", PARSERS, parse_parsers},
{"INSN", INSN, parse_insn},
{"CPU", CPU, parse_cpu},
{"CPU_ALIAS", CPU_ALIAS, parse_cpu_alias},
{"CPU_FEATURE", CPU_FEATURE, parse_cpu_feature},
{"TARGETMOD", TARGETMOD, parse_targetmod},
{"PREFIX", PREFIX, parse_prefix},
{"REG", REG, parse_reg},
{"REGGROUP", REGGROUP, parse_reggroup},
{"SEGREG", SEGREG, parse_segreg},
};
int
main(int argc, char *argv[])
{
FILE *in, *out;
size_t i;
char *tok;
int count[NUM_DIRS];
dir_byp *db;
for (i=0; i<NUM_DIRS; i++)
count[i] = 0;
if (argc != 3) {
fprintf(stderr, "Usage: gap <in> <out>\n");
return EXIT_FAILURE;
}
in = fopen(argv[1], "rt");
if (!in) {
fprintf(stderr, "Could not open `%s' for reading\n", argv[1]);
return EXIT_FAILURE;
}
STAILQ_INIT(&insnprefix_byp);
STAILQ_INIT(&cpu_byp);
STAILQ_INIT(&regtmod_byp);
/* Parse input file */
while (get_line(in)) {
int found;
/*printf("%s\n", line);*/
tok = strtok(line, " \t\n");
if (!tok)
continue;
/* Comments start with # as the first thing on a line */
if (tok[0] == '#')
continue;
/* Look for directive */
found = 0;
for (i=0; i<sizeof(directives)/sizeof(directives[0]); i++) {
if (strcmp(tok, directives[i].name) == 0) {
count[directives[i].indx]++;
directives[i].handler();
found = 1;
break;
}
}
if (!found)
report_error("unknown directive `%s'\n", tok);
}
/* Output some informational statistics */
printf("Directives read:\n");
for (i=0; i<sizeof(directives)/sizeof(directives[0]); i++)
printf("\t%d\t%s\n", count[directives[i].indx], directives[i].name);
if (errors > 0)
return EXIT_FAILURE;
out = fopen(argv[2], "wt");
if (!out) {
fprintf(stderr, "Could not open `%s' for writing\n", argv[2]);
return EXIT_FAILURE;
}
/* Get perfect hashes for the three lists of directives */
STAILQ_FOREACH(db, &insnprefix_byp, link)
perfect_dir(out, "insnprefix", db->parser, &db->dirs);
STAILQ_FOREACH(db, &cpu_byp, link)
perfect_dir(out, "cpu", db->parser, &db->dirs);
STAILQ_FOREACH(db, &regtmod_byp, link)
perfect_dir(out, "regtmod", db->parser, &db->dirs);
if (errors > 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}

@ -0,0 +1,34 @@
# $Id$
# These utility programs have to be built for BUILD host in cross-build.
# This makes things rather non-standard automake
noinst_PROGRAMS += genperf
genperf_SOURCES =
EXTRA_DIST += tools/genperf/genperf.c
EXTRA_DIST += tools/genperf/perfect.c
EXTRA_DIST += tools/genperf/perfect.h
EXTRA_DIST += tools/genperf/standard.h
genperf_LDADD = genperf.$(OBJEXT)
genperf_LDADD += gp-perfect.$(OBJEXT)
genperf_LDADD += gp-phash.$(OBJEXT)
genperf_LDADD += gp-xmalloc.$(OBJEXT)
genperf_LDADD += gp-xstrdup.$(OBJEXT)
genperf_LINK = $(CCLD_FOR_BUILD) -o $@
genperf.$(OBJEXT): tools/genperf/genperf.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/genperf/genperf.c || echo '$(srcdir)/'`tools/genperf/genperf.c
gp-perfect.$(OBJEXT): tools/genperf/perfect.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f tools/genperf/perfect.c || echo '$(srcdir)/'`tools/genperf/perfect.c
gp-phash.$(OBJEXT): libyasm/phash.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/phash.c || echo '$(srcdir)/'`libyasm/phash.c
gp-xmalloc.$(OBJEXT): libyasm/xmalloc.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xmalloc.c || echo '$(srcdir)/'`libyasm/xmalloc.c
gp-xstrdup.$(OBJEXT): libyasm/xstrdup.c
$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/xstrdup.c || echo '$(srcdir)/'`libyasm/xstrdup.c

@ -0,0 +1,519 @@
/* $Id$
*
* Generate Minimal Perfect Hash (genperf)
*
* Copyright (C) 2006-2007 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include "tools/genperf/perfect.h"
#include "libyasm/compat-queue.h"
#include "libyasm/coretype.h"
#include "libyasm/errwarn.h"
typedef STAILQ_HEAD(slist, sval) slist;
typedef struct sval {
STAILQ_ENTRY(sval) link;
char *str;
} sval;
typedef STAILQ_HEAD(keyword_list, keyword) keyword_list;
typedef struct keyword {
STAILQ_ENTRY(keyword) link;
char *name;
char *args;
unsigned int line;
} keyword;
static unsigned int cur_line = 1;
static int errors = 0;
static void
report_error(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%u: ", cur_line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
errors++;
}
void
yasm__fatal(const char *message, ...)
{
abort();
}
/* make the c output for the perfect hash tab array */
static void
make_c_tab(
FILE *f,
bstuff *tab, /* table indexed by b */
ub4 smax, /* range of scramble[] */
ub4 blen, /* b in 0..blen-1, power of 2 */
ub4 *scramble) /* used in final hash */
{
ub4 i;
/* table for the mapping for the perfect hash */
if (blen >= USE_SCRAMBLE) {
/* A way to make the 1-byte values in tab bigger */
if (smax > UB2MAXVAL+1) {
fprintf(f, " static const unsigned long scramble[] = {\n");
for (i=0; i<=UB1MAXVAL; i+=4)
fprintf(f, " 0x%.8lx, 0x%.8lx, 0x%.8lx, 0x%.8lx,\n",
scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3]);
} else {
fprintf(f, " static const unsigned short scramble[] = {\n");
for (i=0; i<=UB1MAXVAL; i+=8)
fprintf(f,
" 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx,\n",
scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3],
scramble[i+4], scramble[i+5], scramble[i+6], scramble[i+7]);
}
fprintf(f, " };\n");
fprintf(f, "\n");
}
if (blen > 0) {
/* small adjustments to _a_ to make values distinct */
if (smax <= UB1MAXVAL+1 || blen >= USE_SCRAMBLE)
fprintf(f, " static const unsigned char ");
else
fprintf(f, " static const unsigned short ");
fprintf(f, "tab[] = {\n");
if (blen < 16) {
for (i=0; i<blen; ++i)
fprintf(f, "%3ld,", scramble[tab[i].val_b]);
} else if (blen <= 1024) {
for (i=0; i<blen; i+=16)
fprintf(f, " %ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
scramble[tab[i+0].val_b], scramble[tab[i+1].val_b],
scramble[tab[i+2].val_b], scramble[tab[i+3].val_b],
scramble[tab[i+4].val_b], scramble[tab[i+5].val_b],
scramble[tab[i+6].val_b], scramble[tab[i+7].val_b],
scramble[tab[i+8].val_b], scramble[tab[i+9].val_b],
scramble[tab[i+10].val_b], scramble[tab[i+11].val_b],
scramble[tab[i+12].val_b], scramble[tab[i+13].val_b],
scramble[tab[i+14].val_b], scramble[tab[i+15].val_b]);
} else if (blen < USE_SCRAMBLE) {
for (i=0; i<blen; i+=8)
fprintf(f, " %ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
scramble[tab[i+0].val_b], scramble[tab[i+1].val_b],
scramble[tab[i+2].val_b], scramble[tab[i+3].val_b],
scramble[tab[i+4].val_b], scramble[tab[i+5].val_b],
scramble[tab[i+6].val_b], scramble[tab[i+7].val_b]);
} else {
for (i=0; i<blen; i+=16)
fprintf(f, " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\n",
tab[i+0].val_b, tab[i+1].val_b,
tab[i+2].val_b, tab[i+3].val_b,
tab[i+4].val_b, tab[i+5].val_b,
tab[i+6].val_b, tab[i+7].val_b,
tab[i+8].val_b, tab[i+9].val_b,
tab[i+10].val_b, tab[i+11].val_b,
tab[i+12].val_b, tab[i+13].val_b,
tab[i+14].val_b, tab[i+15].val_b);
}
fprintf(f, " };\n");
fprintf(f, "\n");
}
}
static void
perfect_gen(FILE *out, const char *lookup_function_name,
const char *struct_name, keyword_list *kws,
const char *filename)
{
ub4 nkeys;
key *keys;
hashform form;
bstuff *tab; /* table indexed by b */
hstuff *tabh; /* table indexed by hash value */
ub4 smax; /* scramble[] values in 0..smax-1, a power of 2 */
ub4 alen; /* a in 0..alen-1, a power of 2 */
ub4 blen; /* b in 0..blen-1, a power of 2 */
ub4 salt; /* a parameter to the hash function */
gencode final; /* code for final hash */
ub4 i;
ub4 scramble[SCRAMBLE_LEN]; /* used in final hash function */
char buf[10][80]; /* buffer for generated code */
char *buf2[10]; /* also for generated code */
keyword *kw;
/* perfect hash configuration */
form.mode = NORMAL_HM;
form.hashtype = STRING_HT;
form.perfect = MINIMAL_HP;
form.speed = SLOW_HS;
/* set up code for final hash */
final.line = buf2;
final.used = 0;
final.len = 10;
for (i=0; i<10; i++)
final.line[i] = buf[i];
/* build list of keys */
nkeys = 0;
keys = NULL;
STAILQ_FOREACH(kw, kws, link) {
key *k = yasm_xmalloc(sizeof(key));
k->name_k = yasm__xstrdup(kw->name);
k->len_k = (ub4)strlen(kw->name);
k->next_k = keys;
keys = k;
nkeys++;
}
/* find the hash */
findhash(&tab, &tabh, &alen, &blen, &salt, &final,
scramble, &smax, keys, nkeys, &form);
/* The hash function beginning */
fprintf(out, "static const struct %s *\n", struct_name);
fprintf(out, "%s(const char *key, size_t len)\n", lookup_function_name);
fprintf(out, "{\n");
/* output the dir table: this should loop up to smax for NORMAL_HP,
* or up to pakd.nkeys for MINIMAL_HP.
*/
fprintf(out, " static const struct %s pd[%lu] = {\n", struct_name, nkeys);
for (i=0; i<nkeys; i++) {
if (tabh[i].key_h) {
sval *sv;
STAILQ_FOREACH(kw, kws, link) {
if (strcmp(kw->name, tabh[i].key_h->name_k) == 0)
break;
}
if (!kw) {
report_error("internal error: could not find `%s'",
tabh[i].key_h->name_k);
break;
}
fprintf(out, "#line %u \"%s\"\n", kw->line, filename);
fprintf(out, " {\"%s\"%s}", kw->name, kw->args);
} else
fprintf(out, " { NULL }");
if (i < nkeys-1)
fprintf(out, ",");
fprintf(out, "\n");
}
fprintf(out, " };\n");
/* output the hash tab[] array */
make_c_tab(out, tab, smax, blen, scramble);
/* The hash function body */
fprintf(out, " const struct %s *ret;\n", struct_name);
for (i=0; i<final.used; ++i)
fprintf(out, final.line[i]);
fprintf(out, " if (rsl >= %lu) return NULL;\n", nkeys);
fprintf(out, " ret = &pd[rsl];\n");
fprintf(out, " if (strcmp(key, ret->name) != 0) return NULL;\n");
fprintf(out, " return ret;\n");
fprintf(out, "}\n");
fprintf(out, "\n");
free(tab);
free(tabh);
}
int
main(int argc, char *argv[])
{
FILE *in;
size_t i;
char *ch;
static char line[1024], tmp[1024];
static char struct_name[128] = "";
static char lookup_function_name[128] = "in_word_set";
static char language[16] = "";
static char delimiters[16] = ",\r\n";
static char name[128];
int need_struct = 0;
int have_struct = 0;
int go_keywords = 0;
int ignore_case = 0;
int compare_strncmp = 0;
int readonly_tables = 0;
slist usercode, usercode2;
keyword_list keywords;
sval *sv;
keyword *kw;
if (argc != 2) {
fprintf(stderr, "Usage: genperf <in>\n");
return EXIT_FAILURE;
}
in = fopen(argv[1], "rt");
if (!in) {
fprintf(stderr, "Could not open `%s' for reading\n", argv[1]);
return EXIT_FAILURE;
}
STAILQ_INIT(&usercode);
STAILQ_INIT(&usercode2);
STAILQ_INIT(&keywords);
/* Parse declarations section */
while (fgets(line, 1024, in)) {
/* Comments start with # as the first thing on a line */
if (line[0] == '#') {
cur_line++;
continue;
}
/* Handle structure declaration */
if (strncmp(line, "struct", 6) == 0) {
int braces;
if (!need_struct) {
report_error("struct without %%struct-type declaration");
return EXIT_FAILURE;
}
if (have_struct) {
report_error("more than one struct declaration");
return EXIT_FAILURE;
}
have_struct = 1;
/* copy struct name */
ch = &line[6];
while (isspace(*ch))
ch++;
i = 0;
while ((isalnum(*ch) || *ch == '_') && i < 127)
struct_name[i++] = *ch++;
if (i == 127) {
report_error("struct name too long");
return EXIT_FAILURE;
}
struct_name[i] = '\0';
sv = yasm_xmalloc(sizeof(sval));
snprintf(tmp, 1024, "#line %u \"%s\"\n", cur_line, argv[1]);
sv->str = yasm__xstrdup(tmp);
STAILQ_INSERT_TAIL(&usercode, sv, link);
braces = 0;
do {
/* count braces to determine when we're done */
ch = line;
while (*ch != '\0') {
if (*ch == '{')
braces++;
if (*ch == '}')
braces--;
ch++;
}
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(line);
STAILQ_INSERT_TAIL(&usercode, sv, link);
cur_line++;
if (braces <= 0)
break;
} while (fgets(line, 1024, in));
cur_line++;
continue;
}
/* Ignore non-declaration lines */
if (line[0] != '%') {
cur_line++;
continue;
}
/* %% terminates declarations section */
if (line[1] == '%') {
if (need_struct && !have_struct) {
report_error("%%struct-type declaration, but no struct found");
return EXIT_FAILURE;
}
go_keywords = 1;
break; /* move on to keywords section */
}
/* %{ begins a verbatim code section that ends with %} */
if (line[1] == '{') {
sv = yasm_xmalloc(sizeof(sval));
snprintf(tmp, 1024, "#line %u \"%s\"\n\n", cur_line, argv[1]);
sv->str = yasm__xstrdup(tmp);
STAILQ_INSERT_TAIL(&usercode, sv, link);
while (fgets(line, 1024, in)) {
cur_line++;
if (line[0] == '%' && line[1] == '}')
break;
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(line);
STAILQ_INSERT_TAIL(&usercode, sv, link);
}
cur_line++;
continue;
}
if (strncmp(&line[1], "ignore-case", 11) == 0) {
ignore_case = 1;
} else if (strncmp(&line[1], "compare-strncmp", 15) == 0) {
compare_strncmp = 1;
} else if (strncmp(&line[1], "readonly-tables", 15) == 0) {
readonly_tables = 1;
} else if (strncmp(&line[1], "language=", 9) == 0) {
ch = &line[10];
i = 0;
while (*ch != '\n' && i<15)
language[i++] = *ch++;
language[i] = '\0';
} else if (strncmp(&line[1], "delimiters=", 11) == 0) {
ch = &line[12];
i = 0;
while (i<15)
delimiters[i++] = *ch++;
delimiters[i] = '\0';
} else if (strncmp(&line[1], "enum", 4) == 0) {
/* unused */
} else if (strncmp(&line[1], "struct-type", 11) == 0) {
need_struct = 1;
} else if (strncmp(&line[1], "define", 6) == 0) {
/* Several different defines we need to handle */
ch = &line[7];
while (isspace(*ch))
ch++;
if (strncmp(ch, "hash-function-name", 18) == 0) {
/* unused */
} else if (strncmp(ch, "lookup-function-name", 20) == 0) {
ch = &line[7+20+1];
while (isspace(*ch))
ch++;
i = 0;
while ((isalnum(*ch) || *ch == '_') && i < 127)
lookup_function_name[i++] = *ch++;
if (i == 127) {
report_error("struct name too long");
return EXIT_FAILURE;
}
lookup_function_name[i] = '\0';
} else {
fprintf(stderr, "%u: unrecognized define `%s'\n", cur_line,
line);
}
} else {
fprintf(stderr, "%u: unrecognized declaration `%s'\n", cur_line,
line);
}
cur_line++;
}
if (!go_keywords) {
report_error("no keywords section found");
return EXIT_FAILURE;
}
/* Parse keywords section */
while (fgets(line, 1024, in)) {
char *d;
/* Comments start with # as the first thing on a line */
if (line[0] == '#') {
cur_line++;
continue;
}
/* Keywords section terminated with %% */
if (line[0] == '%' && line[1] == '%')
break;
/* Look for name */
ch = &line[0];
i = 0;
while (strchr(delimiters, *ch) == NULL && i < 127)
name[i++] = *ch++;
if (i == 127) {
report_error("keyword name too long");
return EXIT_FAILURE;
}
name[i] = '\0';
/* Strip EOL */
d = strrchr(ch, '\n');
if (d)
*d = '\0';
d = strrchr(ch, '\r');
if (d)
*d = '\0';
kw = yasm_xmalloc(sizeof(keyword));
kw->name = yasm__xstrdup(name);
kw->args = yasm__xstrdup(ch);
kw->line = cur_line;
STAILQ_INSERT_TAIL(&keywords, kw, link);
cur_line++;
}
if (errors > 0)
return EXIT_FAILURE;
/* Pull in any end code */
if (!feof(in)) {
sv = yasm_xmalloc(sizeof(sval));
snprintf(tmp, 1024, "#line %u \"%s\"\n\n", cur_line, argv[1]);
sv->str = yasm__xstrdup(tmp);
STAILQ_INSERT_TAIL(&usercode2, sv, link);
while (fgets(line, 1024, in)) {
sv = yasm_xmalloc(sizeof(sval));
sv->str = yasm__xstrdup(line);
STAILQ_INSERT_TAIL(&usercode2, sv, link);
}
}
/* output code */
printf("/* %s code produced by genperf */\n", language);
printf("/* Command-line: genperf %s */\n", argv[1]);
STAILQ_FOREACH(sv, &usercode, link)
printf("%s", sv->str);
/* Get perfect hash */
perfect_gen(stdout, lookup_function_name, struct_name, &keywords, argv[1]);
STAILQ_FOREACH(sv, &usercode2, link)
printf("%s", sv->str);
if (errors > 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}

@ -50,10 +50,10 @@ determined a perfect hash for the whole set of keys.
*/
#include <string.h>
#include "tools/gap/standard.h"
#include "tools/genperf/standard.h"
#include "libyasm/coretype.h"
#include "libyasm/phash.h"
#include "tools/gap/perfect.h"
#include "tools/genperf/perfect.h"
#define CHECKSTATE 8
@ -565,7 +565,7 @@ static int perfect(
if (!augment(tabb, tabh, tabq, blen, scramble, smax, &tabb[i], nkeys,
i+1, form))
{
printf("fail to map group of size %ld for tab size %ld\n", j, blen);
fprintf(stderr, "fail to map group of size %ld for tab size %ld\n", j, blen);
return FALSE;
}
@ -631,7 +631,7 @@ static void hash_ab(
{
if (form->perfect == MINIMAL_HP)
{
printf("fatal error: Cannot find perfect hash for user (A,B) pairs\n");
fprintf(stderr, "fatal error: Cannot find perfect hash for user (A,B) pairs\n");
exit(EXIT_FAILURE);
}
else
@ -644,7 +644,7 @@ static void hash_ab(
nkeys : *smax));
if (!perfect(*tabb, tabh, tabq, *blen, *smax, scramble, nkeys, form))
{
printf("fatal error: Cannot find perfect hash for user (A,B) pairs\n");
fprintf(stderr, "fatal error: Cannot find perfect hash for user (A,B) pairs\n");
exit(EXIT_FAILURE);
}
}
@ -673,7 +673,7 @@ static void hash_ab(
sprintf(final->line[0], " unsigned long rsl = (a ^ scramble[tab[b]]);\n");
}
printf("success, found a perfect hash\n");
fprintf(stderr, "success, found a perfect hash\n");
free((void *)tabq);
free((void *)tabh);
@ -894,7 +894,7 @@ void findhash(
else
{
duplicates(*tabb, *blen, keys, form); /* check for duplicates */
printf("fatal error: Cannot perfect hash: cannot find distinct (A,B)\n");
fprintf(stderr, "fatal error: Cannot perfect hash: cannot find distinct (A,B)\n");
exit(EXIT_FAILURE);
}
bad_initkey = 0;
@ -903,7 +903,7 @@ void findhash(
continue; /* two keys have same (a,b) pair */
}
printf("found distinct (A,B) on attempt %ld\n", trysalt);
fprintf(stderr, "found distinct (A,B) on attempt %ld\n", trysalt);
/* Given distinct (A,B) for all keys, build a perfect hash */
if (!perfect(*tabb, *tabh, tabq, *blen, *smax, scramble, nkeys, form))
@ -922,7 +922,7 @@ void findhash(
}
else
{
printf("fatal error: Cannot perfect hash: cannot build tab[]\n");
fprintf(stderr, "fatal error: Cannot perfect hash: cannot build tab[]\n");
exit(EXIT_FAILURE);
}
bad_perfect = 0;
@ -934,7 +934,7 @@ void findhash(
break;
}
printf("built perfect hash table of size %ld\n", *blen);
fprintf(stderr, "built perfect hash table of size %ld\n", *blen);
/* free working memory */
free((void *)tabq);
Loading…
Cancel
Save