mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 02:50:08 +08:00
* cgen-asm.c (cgen_current_opcode_table): Renamed from ..._data.
(asm_hash_table_entries): New variable. (cgen_asm_init): Free asm_hash_table_entries. (hash_insn_array,hash_insn_list): New functions. (build_asm_hash_table): Use them. Hash macro insns as well. (cgen_asm_lookup_insn): Update. * cgen_dis.c (cgen_current_opcode_table): Renamed from ..._data. (dis_hash_table_entries): New variable. (cgen_dis_init): Free dis_hash_table_entries. (hash_insn_array,hash_insn_list): New functions. (build_dis_hash_table): Use them. Hash macro insns as well. (cgen_dis_lookup_insn): Update. * cgen-opc.c (cgen_current_opcode_table): Renamed from ..._data. (cgen_set_cpu,cgen_hw_lookup,cgen_insn_count): Update. (cgen_macro_insn_count): New function. * cgen-opc.in (@arch@_cgen_lookup_insn): New arg alias_p. All callers updated. Sanity check result of extract fn. (@arch@_cgen_get_insn_operands): Change result type to void. Delete args insn_value, length. New arg fields. All callers updated. (@arch@_cgen_lookup_get_insn_operands): New function.
This commit is contained in:
@ -1,3 +1,26 @@
|
|||||||
|
Mon Apr 27 10:33:56 1998 Doug Evans <devans@seba.cygnus.com>
|
||||||
|
|
||||||
|
* cgen-asm.c (cgen_current_opcode_table): Renamed from ..._data.
|
||||||
|
(asm_hash_table_entries): New variable.
|
||||||
|
(cgen_asm_init): Free asm_hash_table_entries.
|
||||||
|
(hash_insn_array,hash_insn_list): New functions.
|
||||||
|
(build_asm_hash_table): Use them. Hash macro insns as well.
|
||||||
|
(cgen_asm_lookup_insn): Update.
|
||||||
|
* cgen_dis.c (cgen_current_opcode_table): Renamed from ..._data.
|
||||||
|
(dis_hash_table_entries): New variable.
|
||||||
|
(cgen_dis_init): Free dis_hash_table_entries.
|
||||||
|
(hash_insn_array,hash_insn_list): New functions.
|
||||||
|
(build_dis_hash_table): Use them. Hash macro insns as well.
|
||||||
|
(cgen_dis_lookup_insn): Update.
|
||||||
|
* cgen-opc.c (cgen_current_opcode_table): Renamed from ..._data.
|
||||||
|
(cgen_set_cpu,cgen_hw_lookup,cgen_insn_count): Update.
|
||||||
|
(cgen_macro_insn_count): New function.
|
||||||
|
* cgen-opc.in (@arch@_cgen_lookup_insn): New arg alias_p.
|
||||||
|
All callers updated. Sanity check result of extract fn.
|
||||||
|
(@arch@_cgen_get_insn_operands): Change result type to void.
|
||||||
|
Delete args insn_value, length. New arg fields. All callers updated.
|
||||||
|
(@arch@_cgen_lookup_get_insn_operands): New function.
|
||||||
|
|
||||||
Fri Apr 24 16:07:57 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
|
Fri Apr 24 16:07:57 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
|
||||||
|
|
||||||
* i386-dis.c (OP_DSSI): Print segment override.
|
* i386-dis.c (OP_DSSI): Print segment override.
|
||||||
|
@ -1,34 +1,30 @@
|
|||||||
/* CGEN generic assembler support code.
|
/* CGEN generic assembler support code.
|
||||||
|
|
||||||
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of the GNU Binutils and GDB, the GNU debugger.
|
This file is part of the GNU Binutils and GDB, the GNU debugger.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2, or (at your option)
|
the Free Software Foundation; either version 2, or (at your option)
|
||||||
any later version.
|
any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
#include "config.h"
|
#include "sysdep.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifdef HAVE_STRING_H
|
#include <ctype.h>
|
||||||
#include <string.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STRINGS_H
|
|
||||||
#include <strings.h>
|
|
||||||
#endif
|
|
||||||
#include "ansidecl.h"
|
#include "ansidecl.h"
|
||||||
#include "libiberty.h"
|
#include "libiberty.h"
|
||||||
#include "bfd.h"
|
#include "bfd.h"
|
||||||
|
#include "symcat.h"
|
||||||
#include "opcode/cgen.h"
|
#include "opcode/cgen.h"
|
||||||
|
|
||||||
/* Operand parsing callback. */
|
/* Operand parsing callback. */
|
||||||
@ -38,10 +34,11 @@ const char * (*cgen_parse_operand_fn)
|
|||||||
|
|
||||||
/* This is not published as part of the public interface so we don't
|
/* This is not published as part of the public interface so we don't
|
||||||
declare this in cgen.h. */
|
declare this in cgen.h. */
|
||||||
extern CGEN_OPCODE_DATA *cgen_current_opcode_data;
|
extern CGEN_OPCODE_TABLE *cgen_current_opcode_table;
|
||||||
|
|
||||||
/* Assembler instruction hash table. */
|
/* Assembler instruction hash table. */
|
||||||
static CGEN_INSN_LIST **asm_hash_table;
|
static CGEN_INSN_LIST **asm_hash_table;
|
||||||
|
static CGEN_INSN_LIST *asm_hash_table_entries;
|
||||||
|
|
||||||
/* Called once at startup and whenever machine/endian change. */
|
/* Called once at startup and whenever machine/endian change. */
|
||||||
|
|
||||||
@ -51,7 +48,9 @@ cgen_asm_init ()
|
|||||||
if (asm_hash_table)
|
if (asm_hash_table)
|
||||||
{
|
{
|
||||||
free (asm_hash_table);
|
free (asm_hash_table);
|
||||||
|
free (asm_hash_table_entries);
|
||||||
asm_hash_table = NULL;
|
asm_hash_table = NULL;
|
||||||
|
asm_hash_table_entries = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,61 +64,131 @@ cgen_init_parse_operand ()
|
|||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subroutine of build_asm_hash_table to add INSNS to the hash table.
|
||||||
|
|
||||||
|
COUNT is the number of elements in INSNS.
|
||||||
|
ENTSIZE is sizeof (CGEN_INSN) for the target.
|
||||||
|
This is a bit tricky as the size of the attribute member of CGEN_INSN
|
||||||
|
is variable among architectures. This code could be moved to
|
||||||
|
cgen-asm.in, but I prefer to keep it here for now.
|
||||||
|
OTABLE is the opcode table.
|
||||||
|
HTABLE points to the hash table.
|
||||||
|
HENTBUF is a pointer to sufficiently large buffer of hash entries.
|
||||||
|
The result is a pointer to the next entry to use.
|
||||||
|
|
||||||
|
The table is scanned backwards as additions are made to the front of the
|
||||||
|
list and we want earlier ones to be prefered. */
|
||||||
|
|
||||||
|
static CGEN_INSN_LIST *
|
||||||
|
hash_insn_array (insns, count, entsize, otable, htable, hentbuf)
|
||||||
|
const CGEN_INSN * insns;
|
||||||
|
int count;
|
||||||
|
int entsize;
|
||||||
|
const CGEN_OPCODE_TABLE * otable;
|
||||||
|
CGEN_INSN_LIST ** htable;
|
||||||
|
CGEN_INSN_LIST * hentbuf;
|
||||||
|
{
|
||||||
|
const CGEN_INSN * insn;
|
||||||
|
|
||||||
|
for (insn = (CGEN_INSN *) ((char *) insns + entsize * (count - 1));
|
||||||
|
insn >= insns;
|
||||||
|
insn = (CGEN_INSN *) ((char *) insn - entsize), ++ hentbuf)
|
||||||
|
{
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (! (*otable->asm_hash_p) (insn))
|
||||||
|
continue;
|
||||||
|
hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (insn));
|
||||||
|
hentbuf->next = htable[hash];
|
||||||
|
hentbuf->insn = insn;
|
||||||
|
htable[hash] = hentbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hentbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subroutine of build_asm_hash_table to add INSNS to the hash table.
|
||||||
|
This function is identical to hash_insn_array except the insns are
|
||||||
|
in a list. */
|
||||||
|
|
||||||
|
static CGEN_INSN_LIST *
|
||||||
|
hash_insn_list (insns, otable, htable, hentbuf)
|
||||||
|
const CGEN_INSN_LIST * insns;
|
||||||
|
const CGEN_OPCODE_TABLE * otable;
|
||||||
|
CGEN_INSN_LIST ** htable;
|
||||||
|
CGEN_INSN_LIST * hentbuf;
|
||||||
|
{
|
||||||
|
const CGEN_INSN_LIST * ilist;
|
||||||
|
|
||||||
|
for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
|
||||||
|
{
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (! (*otable->asm_hash_p) (ilist->insn))
|
||||||
|
continue;
|
||||||
|
hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (ilist->insn));
|
||||||
|
hentbuf->next = htable[hash];
|
||||||
|
hentbuf->insn = ilist->insn;
|
||||||
|
asm_hash_table[hash] = hentbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hentbuf;
|
||||||
|
}
|
||||||
|
|
||||||
/* Build the assembler instruction hash table. */
|
/* Build the assembler instruction hash table. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
build_asm_hash_table ()
|
build_asm_hash_table ()
|
||||||
{
|
{
|
||||||
int i;
|
int count = cgen_insn_count () + cgen_macro_insn_count ();
|
||||||
unsigned int hash;
|
CGEN_OPCODE_TABLE *opcode_table = cgen_current_opcode_table;
|
||||||
int count = cgen_insn_count ();
|
CGEN_INSN_TABLE *insn_table = opcode_table->insn_table;
|
||||||
CGEN_OPCODE_DATA *data = cgen_current_opcode_data;
|
CGEN_INSN_TABLE *macro_insn_table = opcode_table->macro_insn_table;
|
||||||
CGEN_INSN_TABLE *insn_table = data->insn_table;
|
unsigned int hash_size = opcode_table->asm_hash_table_size;
|
||||||
unsigned int hash_size = insn_table->asm_hash_table_size;
|
CGEN_INSN_LIST *hash_entry_buf;
|
||||||
const CGEN_INSN *insn;
|
|
||||||
CGEN_INSN_LIST *insn_lists,*new_insns;
|
|
||||||
|
|
||||||
/* The space allocated for the hash table consists of two parts:
|
/* The space allocated for the hash table consists of two parts:
|
||||||
the hash table and the hash lists. */
|
the hash table and the hash lists. */
|
||||||
|
|
||||||
asm_hash_table = (CGEN_INSN_LIST **)
|
asm_hash_table = (CGEN_INSN_LIST **)
|
||||||
xmalloc (hash_size * sizeof (CGEN_INSN_LIST *)
|
xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
|
||||||
+ count * sizeof (CGEN_INSN_LIST));
|
memset (asm_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
|
||||||
memset (asm_hash_table, 0,
|
asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
|
||||||
hash_size * sizeof (CGEN_INSN_LIST *)
|
xmalloc (count * sizeof (CGEN_INSN_LIST));
|
||||||
+ count * sizeof (CGEN_INSN_LIST));
|
|
||||||
insn_lists = (CGEN_INSN_LIST *) (asm_hash_table + hash_size);
|
|
||||||
|
|
||||||
/* Add compiled in insns.
|
/* Add compiled in insns.
|
||||||
The table is scanned backwards as later additions are inserted in
|
Don't include the first one as it is a reserved entry. */
|
||||||
front of earlier ones and we want earlier ones to be prefered.
|
/* ??? It was the end of all hash chains, and also the special
|
||||||
We stop at the first one as it is a reserved entry. */
|
"illegal insn" marker. May be able to do it differently now. */
|
||||||
|
|
||||||
for (insn = insn_table->init_entries + insn_table->num_init_entries - 1;
|
hash_entry_buf = hash_insn_array ((CGEN_INSN *) ((char *) insn_table->init_entries
|
||||||
insn > insn_table->init_entries;
|
+ insn_table->entry_size),
|
||||||
--insn, ++insn_lists)
|
insn_table->num_init_entries - 1,
|
||||||
{
|
insn_table->entry_size,
|
||||||
hash = (*insn_table->asm_hash) (insn->syntax.mnemonic);
|
opcode_table, asm_hash_table, hash_entry_buf);
|
||||||
insn_lists->next = asm_hash_table[hash];
|
|
||||||
insn_lists->insn = insn;
|
/* Add compiled in macro-insns. */
|
||||||
asm_hash_table[hash] = insn_lists;
|
|
||||||
}
|
hash_entry_buf = hash_insn_array (macro_insn_table->init_entries,
|
||||||
|
macro_insn_table->num_init_entries,
|
||||||
|
macro_insn_table->entry_size,
|
||||||
|
opcode_table, asm_hash_table, hash_entry_buf);
|
||||||
|
|
||||||
/* Add runtime added insns.
|
/* Add runtime added insns.
|
||||||
??? Currently later added insns will be prefered over earlier ones.
|
Later added insns will be prefered over earlier ones. */
|
||||||
Not sure this is a bug or not. */
|
|
||||||
for (new_insns = insn_table->new_entries;
|
hash_entry_buf = hash_insn_list (insn_table->new_entries, opcode_table,
|
||||||
new_insns != NULL;
|
asm_hash_table, hash_entry_buf);
|
||||||
new_insns = new_insns->next, ++insn_lists)
|
|
||||||
{
|
/* Add runtime added macro-insns. */
|
||||||
hash = (*insn_table->asm_hash) (new_insns->insn->syntax.mnemonic);
|
|
||||||
insn_lists->next = asm_hash_table[hash];
|
hash_insn_list (macro_insn_table->new_entries,
|
||||||
insn_lists->insn = new_insns->insn;
|
opcode_table, asm_hash_table, hash_entry_buf);
|
||||||
asm_hash_table[hash] = insn_lists;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the first entry in the hash list for INSN. */
|
/* Return the first entry in the hash list for INSN.
|
||||||
|
??? Of course it would be better to pass in a pointer to the
|
||||||
|
opcode data structure, rather than reference a global. Later. */
|
||||||
|
|
||||||
CGEN_INSN_LIST *
|
CGEN_INSN_LIST *
|
||||||
cgen_asm_lookup_insn (insn)
|
cgen_asm_lookup_insn (insn)
|
||||||
@ -130,7 +199,7 @@ cgen_asm_lookup_insn (insn)
|
|||||||
if (asm_hash_table == NULL)
|
if (asm_hash_table == NULL)
|
||||||
build_asm_hash_table ();
|
build_asm_hash_table ();
|
||||||
|
|
||||||
hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn);
|
hash = (*cgen_current_opcode_table->asm_hash) (insn);
|
||||||
return asm_hash_table[hash];
|
return asm_hash_table[hash];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,35 +214,40 @@ cgen_asm_lookup_insn (insn)
|
|||||||
const char *
|
const char *
|
||||||
cgen_parse_keyword (strp, keyword_table, valuep)
|
cgen_parse_keyword (strp, keyword_table, valuep)
|
||||||
const char **strp;
|
const char **strp;
|
||||||
struct cgen_keyword *keyword_table;
|
CGEN_KEYWORD *keyword_table;
|
||||||
long *valuep;
|
long *valuep;
|
||||||
{
|
{
|
||||||
const struct cgen_keyword_entry *ke;
|
const CGEN_KEYWORD_ENTRY *ke;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
const char *p;
|
const char *p,*start;
|
||||||
|
|
||||||
p = *strp;
|
p = start = *strp;
|
||||||
|
|
||||||
/* Allow any first character. */
|
/* Allow any first character.
|
||||||
|
Note that this allows recognizing ",a" for the annul flag in sparc
|
||||||
|
even though "," is subsequently not a valid keyword char. */
|
||||||
if (*p)
|
if (*p)
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
/* Now allow letters, digits, and _. */
|
/* Now allow letters, digits, and _. */
|
||||||
while (isalnum (*p) || *p == '_')
|
while (((p - start) < (int) sizeof (buf))
|
||||||
|
&& (isalnum ((unsigned char) *p) || *p == '_'))
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
if (p - *strp > 255)
|
if (p - start >= (int) sizeof (buf))
|
||||||
return "unrecognized keyword/register name";
|
return "unrecognized keyword/register name";
|
||||||
|
|
||||||
memcpy (buf, *strp, p - *strp);
|
memcpy (buf, start, p - start);
|
||||||
buf[p - *strp] = 0;
|
buf[p - start] = 0;
|
||||||
|
|
||||||
ke = cgen_keyword_lookup_name (keyword_table, buf);
|
ke = cgen_keyword_lookup_name (keyword_table, buf);
|
||||||
|
|
||||||
if (ke != NULL)
|
if (ke != NULL)
|
||||||
{
|
{
|
||||||
*valuep = ke->value;
|
*valuep = ke->value;
|
||||||
*strp = p;
|
/* Don't advance pointer if we recognized the null keyword. */
|
||||||
|
if (ke->name[0] != 0)
|
||||||
|
*strp = p;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,13 +257,12 @@ cgen_parse_keyword (strp, keyword_table, valuep)
|
|||||||
/* Signed integer parser. */
|
/* Signed integer parser. */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
cgen_parse_signed_integer (strp, opindex, min, max, valuep)
|
cgen_parse_signed_integer (strp, opindex, valuep)
|
||||||
const char **strp;
|
const char **strp;
|
||||||
int opindex;
|
int opindex;
|
||||||
long min, max;
|
|
||||||
long *valuep;
|
long *valuep;
|
||||||
{
|
{
|
||||||
long value;
|
bfd_vma value;
|
||||||
enum cgen_parse_operand_result result;
|
enum cgen_parse_operand_result result;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
|
||||||
@ -198,24 +271,19 @@ cgen_parse_signed_integer (strp, opindex, min, max, valuep)
|
|||||||
&result, &value);
|
&result, &value);
|
||||||
/* FIXME: Examine `result'. */
|
/* FIXME: Examine `result'. */
|
||||||
if (!errmsg)
|
if (!errmsg)
|
||||||
{
|
*valuep = value;
|
||||||
if (value < min || value > max)
|
|
||||||
return "integer operand out of range";
|
|
||||||
*valuep = value;
|
|
||||||
}
|
|
||||||
return errmsg;
|
return errmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unsigned integer parser. */
|
/* Unsigned integer parser. */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
cgen_parse_unsigned_integer (strp, opindex, min, max, valuep)
|
cgen_parse_unsigned_integer (strp, opindex, valuep)
|
||||||
const char **strp;
|
const char **strp;
|
||||||
int opindex;
|
int opindex;
|
||||||
unsigned long min, max;
|
|
||||||
unsigned long *valuep;
|
unsigned long *valuep;
|
||||||
{
|
{
|
||||||
unsigned long value;
|
bfd_vma value;
|
||||||
enum cgen_parse_operand_result result;
|
enum cgen_parse_operand_result result;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
|
||||||
@ -224,33 +292,32 @@ cgen_parse_unsigned_integer (strp, opindex, min, max, valuep)
|
|||||||
&result, &value);
|
&result, &value);
|
||||||
/* FIXME: Examine `result'. */
|
/* FIXME: Examine `result'. */
|
||||||
if (!errmsg)
|
if (!errmsg)
|
||||||
{
|
*valuep = value;
|
||||||
if (value < min || value > max)
|
|
||||||
return "integer operand out of range";
|
|
||||||
*valuep = value;
|
|
||||||
}
|
|
||||||
return errmsg;
|
return errmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Address parser. */
|
/* Address parser. */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
cgen_parse_address (strp, opindex, opinfo, valuep)
|
cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
|
||||||
const char **strp;
|
const char **strp;
|
||||||
int opindex;
|
int opindex;
|
||||||
int opinfo;
|
int opinfo;
|
||||||
|
enum cgen_parse_operand_result *resultp;
|
||||||
long *valuep;
|
long *valuep;
|
||||||
{
|
{
|
||||||
long value;
|
bfd_vma value;
|
||||||
enum cgen_parse_operand_result result;
|
enum cgen_parse_operand_result result_type;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
|
||||||
errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
|
errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
|
||||||
opindex, opinfo,
|
opindex, opinfo,
|
||||||
&result, &value);
|
&result_type, &value);
|
||||||
/* FIXME: Examine `result'. */
|
/* FIXME: Examine `result'. */
|
||||||
if (!errmsg)
|
if (!errmsg)
|
||||||
{
|
{
|
||||||
|
if (resultp != NULL)
|
||||||
|
*resultp = result_type;
|
||||||
*valuep = value;
|
*valuep = value;
|
||||||
}
|
}
|
||||||
return errmsg;
|
return errmsg;
|
||||||
|
@ -30,10 +30,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|||||||
#include "@arch@-opc.h"
|
#include "@arch@-opc.h"
|
||||||
|
|
||||||
/* Look up instruction INSN_VALUE and extract its fields.
|
/* Look up instruction INSN_VALUE and extract its fields.
|
||||||
If non-null INSN is the insn table entry.
|
INSN, if non-null, is the insn table entry.
|
||||||
Otherwise INSN_VALUE is examined to compute it.
|
Otherwise INSN_VALUE is examined to compute it.
|
||||||
LENGTH is the bit length of INSN_VALUE if known, otherwise 0.
|
LENGTH is the bit length of INSN_VALUE if known, otherwise 0.
|
||||||
|
0 is only valid if `insn == NULL && ! defined (CGEN_INT_INSN)'.
|
||||||
|
If INSN != NULL, LENGTH must be valid.
|
||||||
ALIAS_P is non-zero if alias insns are to be included in the search.
|
ALIAS_P is non-zero if alias insns are to be included in the search.
|
||||||
|
|
||||||
The result a pointer to the insn table entry, or NULL if the instruction
|
The result a pointer to the insn table entry, or NULL if the instruction
|
||||||
wasn't recognized. */
|
wasn't recognized. */
|
||||||
|
|
||||||
@ -43,6 +46,7 @@ const CGEN_INSN *
|
|||||||
cgen_insn_t insn_value;
|
cgen_insn_t insn_value;
|
||||||
int length;
|
int length;
|
||||||
CGEN_FIELDS *fields;
|
CGEN_FIELDS *fields;
|
||||||
|
int alias_p;
|
||||||
{
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
|
|
||||||
@ -91,9 +95,15 @@ const CGEN_INSN *
|
|||||||
extract handler. */
|
extract handler. */
|
||||||
if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
|
if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
|
||||||
{
|
{
|
||||||
length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, fields);
|
int elength = (*CGEN_EXTRACT_FN (insn)) (insn, NULL,
|
||||||
if (length > 0)
|
insn_value, fields);
|
||||||
return insn;
|
if (elength > 0)
|
||||||
|
{
|
||||||
|
/* sanity check */
|
||||||
|
if (length != 0 && length != elength)
|
||||||
|
abort ();
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,43 +116,34 @@ const CGEN_INSN *
|
|||||||
if (! alias_p
|
if (! alias_p
|
||||||
&& CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS))
|
&& CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS))
|
||||||
abort ();
|
abort ();
|
||||||
|
/* Sanity check: length must be correct. */
|
||||||
|
if (length != CGEN_INSN_BITSIZE (insn))
|
||||||
|
abort ();
|
||||||
|
|
||||||
length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, fields);
|
length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, fields);
|
||||||
if (length > 0)
|
/* Sanity check: must succeed.
|
||||||
return insn;
|
Could relax this later if it ever proves useful. */
|
||||||
|
if (length == 0)
|
||||||
|
abort ();
|
||||||
|
return insn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the operand instances used by insn INSN_VALUE.
|
/* Fill in the operand instances used by INSN whose operands are FIELDS.
|
||||||
If non-null INS is the insn table entry.
|
|
||||||
Otherwise INSN_VALUE is examined to compute it.
|
|
||||||
LENGTH is the number of bits in INSN_VALUE if known, otherwise 0.
|
|
||||||
INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
|
INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
|
||||||
in.
|
in. */
|
||||||
The result a pointer to the insn table entry, or NULL if the instruction
|
|
||||||
wasn't recognized. */
|
|
||||||
|
|
||||||
const CGEN_INSN *
|
void
|
||||||
@arch@_cgen_get_insn_operands (insn, insn_value, length, indices)
|
@arch@_cgen_get_insn_operands (insn, fields, indices)
|
||||||
const CGEN_INSN *insn;
|
const CGEN_INSN * insn;
|
||||||
cgen_insn_t insn_value;
|
const CGEN_FIELDS * fields;
|
||||||
int length;
|
|
||||||
int *indices;
|
int *indices;
|
||||||
{
|
{
|
||||||
CGEN_FIELDS fields;
|
|
||||||
const CGEN_OPERAND_INSTANCE *opinst;
|
const CGEN_OPERAND_INSTANCE *opinst;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* FIXME: ALIAS insns are in transition from being record in the insn table
|
|
||||||
to being recorded separately as macros. They don't have semantic code
|
|
||||||
so they can't be used here. Thus we currently always ignore the INSN
|
|
||||||
argument. */
|
|
||||||
insn = @arch@_cgen_lookup_insn (NULL, insn_value, length, &fields, 0);
|
|
||||||
if (! insn)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (i = 0, opinst = CGEN_INSN_OPERANDS (insn);
|
for (i = 0, opinst = CGEN_INSN_OPERANDS (insn);
|
||||||
opinst != NULL
|
opinst != NULL
|
||||||
&& CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
|
&& CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
|
||||||
@ -152,8 +153,34 @@ const CGEN_INSN *
|
|||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
indices[i] = CGEN_OPERAND_INSTANCE_INDEX (opinst);
|
indices[i] = CGEN_OPERAND_INSTANCE_INDEX (opinst);
|
||||||
else
|
else
|
||||||
indices[i] = @arch@_cgen_get_operand (CGEN_OPERAND_INDEX (op), &fields);
|
indices[i] = @arch@_cgen_get_operand (CGEN_OPERAND_INDEX (op), fields);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cover function to @arch@_cgen_get_insn_operands when either INSN or FIELDS
|
||||||
|
isn't known.
|
||||||
|
The INSN, INSN_VALUE, and LENGTH arguments are passed to
|
||||||
|
@arch@_cgen_lookup_insn unchanged.
|
||||||
|
|
||||||
|
The result is the insn table entry or NULL if the instruction wasn't
|
||||||
|
recognized. */
|
||||||
|
|
||||||
|
const CGEN_INSN *
|
||||||
|
@arch@_cgen_lookup_get_insn_operands (insn, insn_value, length, indices)
|
||||||
|
const CGEN_INSN *insn;
|
||||||
|
cgen_insn_t insn_value;
|
||||||
|
int length;
|
||||||
|
int *indices;
|
||||||
|
{
|
||||||
|
CGEN_FIELDS fields;
|
||||||
|
|
||||||
|
/* Pass non-zero for ALIAS_P only if INSN != NULL.
|
||||||
|
If INSN == NULL, we want a real insn. */
|
||||||
|
insn = @arch@_cgen_lookup_insn (insn, insn_value, length, &fields,
|
||||||
|
insn != NULL);
|
||||||
|
if (! insn)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
@arch@_cgen_get_insn_operands (insn, &fields, indices);
|
||||||
return insn;
|
return insn;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user