184865Sobrien/* ia64-gen.c -- Generate a shrunk set of opcode tables
2218822Sdim   Copyright 1999, 2000, 2001, 2002, 2004, 2005, 2006
3218822Sdim   Free Software Foundation, Inc.
484865Sobrien   Written by Bob Manson, Cygnus Solutions, <manson@cygnus.com>
584865Sobrien
684865Sobrien   This file is part of GDB, GAS, and the GNU binutils.
784865Sobrien
884865Sobrien   GDB, GAS, and the GNU binutils are free software; you can redistribute
984865Sobrien   them and/or modify them under the terms of the GNU General Public
1084865Sobrien   License as published by the Free Software Foundation; either version
1184865Sobrien   2, or (at your option) any later version.
1284865Sobrien
1384865Sobrien   GDB, GAS, and the GNU binutils are distributed in the hope that they
1484865Sobrien   will be useful, but WITHOUT ANY WARRANTY; without even the implied
1584865Sobrien   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1684865Sobrien   the GNU General Public License for more details.
1784865Sobrien
1884865Sobrien   You should have received a copy of the GNU General Public License
1984865Sobrien   along with this file; see the file COPYING.  If not, write to the
20218822Sdim   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2284865Sobrien
2384865Sobrien/* While the ia64-opc-* set of opcode tables are easy to maintain,
2484865Sobrien   they waste a tremendous amount of space.  ia64-gen rearranges the
2584865Sobrien   instructions into a directed acyclic graph (DAG) of instruction opcodes and
2684865Sobrien   their possible completers, as well as compacting the set of strings used.
2784865Sobrien
2884865Sobrien   The disassembler table consists of a state machine that does
2984865Sobrien   branching based on the bits of the opcode being disassembled.  The
3084865Sobrien   state encodings have been chosen to minimize the amount of space
3184865Sobrien   required.
3284865Sobrien
3384865Sobrien   The resource table is constructed based on some text dependency tables,
34130561Sobrien   which are also easier to maintain than the final representation.  */
3584865Sobrien
3684865Sobrien#include <stdio.h>
37130561Sobrien#include <stdarg.h>
38130561Sobrien#include <errno.h>
3984865Sobrien
4084865Sobrien#include "ansidecl.h"
4184865Sobrien#include "libiberty.h"
4289857Sobrien#include "safe-ctype.h"
4384865Sobrien#include "sysdep.h"
44130561Sobrien#include "getopt.h"
4584865Sobrien#include "ia64-opc.h"
4684865Sobrien#include "ia64-opc-a.c"
4784865Sobrien#include "ia64-opc-i.c"
4884865Sobrien#include "ia64-opc-m.c"
4984865Sobrien#include "ia64-opc-b.c"
5084865Sobrien#include "ia64-opc-f.c"
5184865Sobrien#include "ia64-opc-x.c"
5284865Sobrien#include "ia64-opc-d.c"
5384865Sobrien
54130561Sobrien#include <libintl.h>
55130561Sobrien#define _(String) gettext (String)
56130561Sobrien
57218822Sdim/* This is a copy of fprintf_vma from bfd/bfd-in2.h.  We have to use this
58218822Sdim   always, because we might be compiled without BFD64 defined, if configured
59218822Sdim   for a 32-bit target and --enable-targets=all is used.  This will work for
60218822Sdim   both 32-bit and 64-bit hosts.  */
61218822Sdim#define _opcode_int64_low(x) ((unsigned long) (((x) & 0xffffffff)))
62218822Sdim#define _opcode_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff))
63218822Sdim#define opcode_fprintf_vma(s,x) \
64218822Sdim  fprintf ((s), "%08lx%08lx", _opcode_int64_high (x), _opcode_int64_low (x))
65218822Sdim
66130561Sobrienconst char * program_name = NULL;
6784865Sobrienint debug = 0;
6884865Sobrien
69218822Sdim#define NELEMS(a) (sizeof (a) / sizeof ((a)[0]))
7084865Sobrien#define tmalloc(X) (X *) xmalloc (sizeof (X))
7184865Sobrien
7284865Sobrien/* The main opcode table entry.  Each entry is a unique combination of
7384865Sobrien   name and flags (no two entries in the table compare as being equal
74130561Sobrien   via opcodes_eq).  */
7584865Sobrienstruct main_entry
7684865Sobrien{
7784865Sobrien  /* The base name of this opcode.  The names of its completers are
78130561Sobrien     appended to it to generate the full instruction name.  */
7984865Sobrien  struct string_entry *name;
8084865Sobrien  /* The base opcode entry.  Which one to use is a fairly arbitrary choice;
81130561Sobrien     it uses the first one passed to add_opcode_entry.  */
8284865Sobrien  struct ia64_opcode *opcode;
83130561Sobrien  /* The list of completers that can be applied to this opcode.  */
8484865Sobrien  struct completer_entry *completers;
85130561Sobrien  /* Next entry in the chain.  */
8684865Sobrien  struct main_entry *next;
87130561Sobrien  /* Index in the  main table.  */
8884865Sobrien  int main_index;
8984865Sobrien} *maintable, **ordered_table;
90130561Sobrien
9184865Sobrienint otlen = 0;
9284865Sobrienint ottotlen = 0;
9384865Sobrienint opcode_count = 0;
9484865Sobrien
95130561Sobrien/* The set of possible completers for an opcode.  */
9684865Sobrienstruct completer_entry
9784865Sobrien{
98130561Sobrien  /* This entry's index in the ia64_completer_table[] array.  */
9984865Sobrien  int num;
10084865Sobrien
101130561Sobrien  /* The name of the completer.  */
10284865Sobrien  struct string_entry *name;
10384865Sobrien
104130561Sobrien  /* This entry's parent.  */
10584865Sobrien  struct completer_entry *parent;
10684865Sobrien
10784865Sobrien  /* Set if this is a terminal completer (occurs at the end of an
108130561Sobrien     opcode).  */
10984865Sobrien  int is_terminal;
11084865Sobrien
111130561Sobrien  /* An alternative completer.  */
11284865Sobrien  struct completer_entry *alternative;
11384865Sobrien
11484865Sobrien  /* Additional completers that can be appended to this one.  */
11584865Sobrien  struct completer_entry *addl_entries;
11684865Sobrien
11784865Sobrien  /* Before compute_completer_bits () is invoked, this contains the actual
11884865Sobrien     instruction opcode for this combination of opcode and completers.
11984865Sobrien     Afterwards, it contains those bits that are different from its
120130561Sobrien     parent opcode.  */
12184865Sobrien  ia64_insn bits;
12284865Sobrien
12384865Sobrien  /* Bits set to 1 correspond to those bits in this completer's opcode
12484865Sobrien     that are different from its parent completer's opcode (or from
12584865Sobrien     the base opcode if the entry is the root of the opcode's completer
126130561Sobrien     list).  This field is filled in by compute_completer_bits ().  */
12784865Sobrien  ia64_insn mask;
12884865Sobrien
129130561Sobrien  /* Index into the opcode dependency list, or -1 if none.  */
13084865Sobrien  int dependencies;
13184865Sobrien
13284865Sobrien  /* Remember the order encountered in the opcode tables.  */
13384865Sobrien  int order;
13484865Sobrien};
13584865Sobrien
136130561Sobrien/* One entry in the disassembler name table.  */
13784865Sobrienstruct disent
13884865Sobrien{
139130561Sobrien  /* The index into the ia64_name_dis array for this entry.  */
14084865Sobrien  int ournum;
14184865Sobrien
142130561Sobrien  /* The index into the main_table[] array.  */
14384865Sobrien  int insn;
14484865Sobrien
145130561Sobrien  /* The disassmbly priority of this entry.  */
14684865Sobrien  int priority;
14784865Sobrien
148130561Sobrien  /* The completer_index value for this entry.  */
14984865Sobrien  int completer_index;
15084865Sobrien
151130561Sobrien  /* How many other entries share this decode.  */
15284865Sobrien  int nextcnt;
15384865Sobrien
154130561Sobrien  /* The next entry sharing the same decode.  */
15584865Sobrien  struct disent *nexte;
15684865Sobrien
157130561Sobrien  /* The next entry in the name list.  */
15884865Sobrien  struct disent *next_ent;
15984865Sobrien} *disinsntable = NULL;
16084865Sobrien
16184865Sobrien/* A state machine that will eventually be used to generate the
162130561Sobrien   disassembler table.  */
16384865Sobrienstruct bittree
16484865Sobrien{
16584865Sobrien  struct disent *disent;
166130561Sobrien  struct bittree *bits[3]; /* 0, 1, and X (don't care).  */
16784865Sobrien  int bits_to_skip;
16884865Sobrien  int skip_flag;
16984865Sobrien} *bittree;
17084865Sobrien
17184865Sobrien/* The string table contains all opcodes and completers sorted in
17284865Sobrien   alphabetical order.  */
17384865Sobrien
174130561Sobrien/* One entry in the string table.  */
17584865Sobrienstruct string_entry
17684865Sobrien{
177130561Sobrien  /* The index in the ia64_strings[] array for this entry.  */
17884865Sobrien  int num;
179130561Sobrien  /* And the string.  */
18084865Sobrien  char *s;
18184865Sobrien} **string_table = NULL;
182130561Sobrien
18384865Sobrienint strtablen = 0;
18484865Sobrienint strtabtotlen = 0;
18584865Sobrien
18684865Sobrien
187130561Sobrien/* Resource dependency entries.  */
18884865Sobrienstruct rdep
18984865Sobrien{
190130561Sobrien  char *name;                       /* Resource name.  */
19184865Sobrien  unsigned
192130561Sobrien    mode:2,                         /* RAW, WAW, or WAR.  */
193130561Sobrien    semantics:3;                    /* Dependency semantics.  */
194130561Sobrien  char *extra;                      /* Additional semantics info.  */
19584865Sobrien  int nchks;
196130561Sobrien  int total_chks;                   /* Total #of terminal insns.  */
197130561Sobrien  int *chks;                        /* Insn classes which read (RAW), write
198130561Sobrien                                       (WAW), or write (WAR) this rsrc.  */
199130561Sobrien  int *chknotes;                    /* Dependency notes for each class.  */
20084865Sobrien  int nregs;
201130561Sobrien  int total_regs;                   /* Total #of terminal insns.  */
202130561Sobrien  int *regs;                        /* Insn class which write (RAW), write2
203130561Sobrien                                       (WAW), or read (WAR) this rsrc.  */
204130561Sobrien  int *regnotes;                    /* Dependency notes for each class.  */
20584865Sobrien
206130561Sobrien  int waw_special;                  /* Special WAW dependency note.  */
20784865Sobrien} **rdeps = NULL;
20884865Sobrien
20984865Sobrienstatic int rdepslen = 0;
21084865Sobrienstatic int rdepstotlen = 0;
21184865Sobrien
212130561Sobrien/* Array of all instruction classes.  */
21384865Sobrienstruct iclass
21484865Sobrien{
215130561Sobrien  char *name;                       /* Instruction class name.  */
216130561Sobrien  int is_class;                     /* Is a class, not a terminal.  */
21784865Sobrien  int nsubs;
218130561Sobrien  int *subs;                        /* Other classes within this class.  */
21984865Sobrien  int nxsubs;
220130561Sobrien  int xsubs[4];                     /* Exclusions.  */
221130561Sobrien  char *comment;                    /* Optional comment.  */
222130561Sobrien  int note;                         /* Optional note.  */
223130561Sobrien  int terminal_resolved;            /* Did we match this with anything?  */
224130561Sobrien  int orphan;                       /* Detect class orphans.  */
22584865Sobrien} **ics = NULL;
22684865Sobrien
22784865Sobrienstatic int iclen = 0;
22884865Sobrienstatic int ictotlen = 0;
22984865Sobrien
230130561Sobrien/* An opcode dependency (chk/reg pair of dependency lists).  */
23184865Sobrienstruct opdep
23284865Sobrien{
23384865Sobrien  int chk;                          /* index into dlists */
23484865Sobrien  int reg;                          /* index into dlists */
23584865Sobrien} **opdeps;
23684865Sobrien
23784865Sobrienstatic int opdeplen = 0;
23884865Sobrienstatic int opdeptotlen = 0;
23984865Sobrien
240130561Sobrien/* A generic list of dependencies w/notes encoded.  These may be shared.  */
24184865Sobrienstruct deplist
24284865Sobrien{
24384865Sobrien  int len;
24484865Sobrien  unsigned short *deps;
24584865Sobrien} **dlists;
24684865Sobrien
24784865Sobrienstatic int dlistlen = 0;
24884865Sobrienstatic int dlisttotlen = 0;
24984865Sobrien
250130561Sobrien
251218822Sdimstatic void fail (const char *, ...) ATTRIBUTE_PRINTF_1;
252218822Sdimstatic void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
253130561Sobrienstatic struct rdep * insert_resource (const char *, enum ia64_dependency_mode);
254130561Sobrienstatic int  deplist_equals (struct deplist *, struct deplist *);
255130561Sobrienstatic short insert_deplist (int, unsigned short *);
256130561Sobrienstatic short insert_dependencies (int, unsigned short *, int, unsigned short *);
257130561Sobrienstatic void  mark_used (struct iclass *, int);
258130561Sobrienstatic int  fetch_insn_class (const char *, int);
259130561Sobrienstatic int  sub_compare (const void *, const void *);
260130561Sobrienstatic void load_insn_classes (void);
261130561Sobrienstatic void parse_resource_users (const char *, int **, int *, int **);
262130561Sobrienstatic int  parse_semantics (char *);
263130561Sobrienstatic void add_dep (const char *, const char *, const char *, int, int, char *, int);
264130561Sobrienstatic void load_depfile (const char *, enum ia64_dependency_mode);
265130561Sobrienstatic void load_dependencies (void);
266130561Sobrienstatic int  irf_operand (int, const char *);
267130561Sobrienstatic int  in_iclass_mov_x (struct ia64_opcode *, struct iclass *, const char *, const char *);
268130561Sobrienstatic int  in_iclass (struct ia64_opcode *, struct iclass *, const char *, const char *, int *);
269130561Sobrienstatic int  lookup_regindex (const char *, int);
270130561Sobrienstatic int  lookup_specifier (const char *);
271130561Sobrienstatic void print_dependency_table (void);
272130561Sobrienstatic struct string_entry * insert_string (char *);
273130561Sobrienstatic void gen_dis_table (struct bittree *);
274130561Sobrienstatic void print_dis_table (void);
275130561Sobrienstatic void generate_disassembler (void);
276130561Sobrienstatic void print_string_table (void);
277130561Sobrienstatic int  completer_entries_eq (struct completer_entry *, struct completer_entry *);
278130561Sobrienstatic struct completer_entry * insert_gclist (struct completer_entry *);
279130561Sobrienstatic int  get_prefix_len (const char *);
280130561Sobrienstatic void compute_completer_bits (struct main_entry *, struct completer_entry *);
281130561Sobrienstatic void collapse_redundant_completers (void);
282130561Sobrienstatic int  insert_opcode_dependencies (struct ia64_opcode *, struct completer_entry *);
283130561Sobrienstatic void insert_completer_entry (struct ia64_opcode *, struct main_entry *, int);
284130561Sobrienstatic void print_completer_entry (struct completer_entry *);
285130561Sobrienstatic void print_completer_table (void);
286130561Sobrienstatic int  opcodes_eq (struct ia64_opcode *, struct ia64_opcode *);
287130561Sobrienstatic void add_opcode_entry (struct ia64_opcode *);
288130561Sobrienstatic void print_main_table (void);
289130561Sobrienstatic void shrink (struct ia64_opcode *);
290130561Sobrienstatic void print_version (void);
291130561Sobrienstatic void usage (FILE *, int);
292130561Sobrienstatic void finish_distable (void);
293130561Sobrienstatic void insert_bit_table_ent (struct bittree *, int, ia64_insn, ia64_insn, int, int, int);
294130561Sobrienstatic void add_dis_entry (struct bittree *, ia64_insn, ia64_insn, int, struct completer_entry *, int);
295130561Sobrienstatic void compact_distree (struct bittree *);
296130561Sobrienstatic struct bittree * make_bittree_entry (void);
297130561Sobrienstatic struct disent * add_dis_table_ent (struct disent *, int, int, int);
298130561Sobrien
299130561Sobrien
300130561Sobrienstatic void
301130561Sobrienfail (const char *message, ...)
302130561Sobrien{
303130561Sobrien  va_list args;
304130561Sobrien
305130561Sobrien  va_start (args, message);
306130561Sobrien  fprintf (stderr, _("%s: Error: "), program_name);
307130561Sobrien  vfprintf (stderr, message, args);
308130561Sobrien  va_end (args);
309130561Sobrien  xexit (1);
310130561Sobrien}
311130561Sobrien
312130561Sobrienstatic void
313130561Sobrienwarn (const char *message, ...)
314130561Sobrien{
315130561Sobrien  va_list args;
316130561Sobrien
317130561Sobrien  va_start (args, message);
318130561Sobrien
319130561Sobrien  fprintf (stderr, _("%s: Warning: "), program_name);
320130561Sobrien  vfprintf (stderr, message, args);
321130561Sobrien  va_end (args);
322130561Sobrien}
323130561Sobrien
324130561Sobrien/* Add NAME to the resource table, where TYPE is RAW or WAW.  */
32584865Sobrienstatic struct rdep *
32684865Sobrieninsert_resource (const char *name, enum ia64_dependency_mode type)
32784865Sobrien{
32884865Sobrien  if (rdepslen == rdepstotlen)
32984865Sobrien    {
33084865Sobrien      rdepstotlen += 20;
33184865Sobrien      rdeps = (struct rdep **)
33284865Sobrien        xrealloc (rdeps, sizeof(struct rdep **) * rdepstotlen);
33384865Sobrien    }
33484865Sobrien  rdeps[rdepslen] = tmalloc(struct rdep);
33584865Sobrien  memset((void *)rdeps[rdepslen], 0, sizeof(struct rdep));
33684865Sobrien  rdeps[rdepslen]->name = xstrdup (name);
33784865Sobrien  rdeps[rdepslen]->mode = type;
33884865Sobrien  rdeps[rdepslen]->waw_special = 0;
33984865Sobrien
34084865Sobrien  return rdeps[rdepslen++];
34184865Sobrien}
34284865Sobrien
343130561Sobrien/* Are the lists of dependency indexes equivalent?  */
34484865Sobrienstatic int
34584865Sobriendeplist_equals (struct deplist *d1, struct deplist *d2)
34684865Sobrien{
34784865Sobrien  int i;
34884865Sobrien
34984865Sobrien  if (d1->len != d2->len)
35084865Sobrien    return 0;
35184865Sobrien
352130561Sobrien  for (i = 0; i < d1->len; i++)
353130561Sobrien    if (d1->deps[i] != d2->deps[i])
354130561Sobrien      return 0;
35584865Sobrien
35684865Sobrien  return 1;
35784865Sobrien}
35884865Sobrien
359130561Sobrien/* Add the list of dependencies to the list of dependency lists.  */
36084865Sobrienstatic short
361130561Sobrieninsert_deplist (int count, unsigned short *deps)
36284865Sobrien{
363130561Sobrien  /* Sort the list, then see if an equivalent list exists already.
364130561Sobrien     this results in a much smaller set of dependency lists.  */
36584865Sobrien  struct deplist *list;
36684865Sobrien  char set[0x10000];
36784865Sobrien  int i;
36884865Sobrien
369130561Sobrien  memset ((void *)set, 0, sizeof (set));
370130561Sobrien  for (i = 0; i < count; i++)
37184865Sobrien    set[deps[i]] = 1;
372130561Sobrien
37384865Sobrien  count = 0;
374130561Sobrien  for (i = 0; i < (int) sizeof (set); i++)
37584865Sobrien    if (set[i])
37684865Sobrien      ++count;
37784865Sobrien
378130561Sobrien  list = tmalloc (struct deplist);
37984865Sobrien  list->len = count;
380130561Sobrien  list->deps = (unsigned short *) malloc (sizeof (unsigned short) * count);
38184865Sobrien
382130561Sobrien  for (i = 0, count = 0; i < (int) sizeof (set); i++)
383130561Sobrien    if (set[i])
384130561Sobrien      list->deps[count++] = i;
38584865Sobrien
386130561Sobrien  /* Does this list exist already?  */
387130561Sobrien  for (i = 0; i < dlistlen; i++)
388130561Sobrien    if (deplist_equals (list, dlists[i]))
389130561Sobrien      {
390130561Sobrien	free (list->deps);
391130561Sobrien	free (list);
392130561Sobrien	return i;
393130561Sobrien      }
394130561Sobrien
39584865Sobrien  if (dlistlen == dlisttotlen)
39684865Sobrien    {
39784865Sobrien      dlisttotlen += 20;
39884865Sobrien      dlists = (struct deplist **)
39984865Sobrien        xrealloc (dlists, sizeof(struct deplist **) * dlisttotlen);
40084865Sobrien    }
40184865Sobrien  dlists[dlistlen] = list;
40284865Sobrien
40384865Sobrien  return dlistlen++;
40484865Sobrien}
40584865Sobrien
406130561Sobrien/* Add the given pair of dependency lists to the opcode dependency list.  */
40784865Sobrienstatic short
40884865Sobrieninsert_dependencies (int nchks, unsigned short *chks,
40984865Sobrien                     int nregs, unsigned short *regs)
41084865Sobrien{
41184865Sobrien  struct opdep *pair;
41284865Sobrien  int i;
41384865Sobrien  int regind = -1;
41484865Sobrien  int chkind = -1;
41584865Sobrien
41684865Sobrien  if (nregs > 0)
41784865Sobrien    regind = insert_deplist (nregs, regs);
41884865Sobrien  if (nchks > 0)
41984865Sobrien    chkind = insert_deplist (nchks, chks);
42084865Sobrien
421130561Sobrien  for (i = 0; i < opdeplen; i++)
422130561Sobrien    if (opdeps[i]->chk == chkind
423130561Sobrien	&& opdeps[i]->reg == regind)
424130561Sobrien      return i;
425130561Sobrien
426130561Sobrien  pair = tmalloc (struct opdep);
42784865Sobrien  pair->chk = chkind;
42884865Sobrien  pair->reg = regind;
42984865Sobrien
43084865Sobrien  if (opdeplen == opdeptotlen)
43184865Sobrien    {
43284865Sobrien      opdeptotlen += 20;
43384865Sobrien      opdeps = (struct opdep **)
43484865Sobrien        xrealloc (opdeps, sizeof(struct opdep **) * opdeptotlen);
43584865Sobrien    }
43684865Sobrien  opdeps[opdeplen] = pair;
43784865Sobrien
43884865Sobrien  return opdeplen++;
43984865Sobrien}
44084865Sobrien
44184865Sobrienstatic void
44284865Sobrienmark_used (struct iclass *ic, int clear_terminals)
44384865Sobrien{
44484865Sobrien  int i;
44584865Sobrien
44684865Sobrien  ic->orphan = 0;
44784865Sobrien  if (clear_terminals)
44884865Sobrien    ic->terminal_resolved = 1;
44984865Sobrien
450130561Sobrien  for (i = 0; i < ic->nsubs; i++)
451130561Sobrien    mark_used (ics[ic->subs[i]], clear_terminals);
452130561Sobrien
453130561Sobrien  for (i = 0; i < ic->nxsubs; i++)
454130561Sobrien    mark_used (ics[ic->xsubs[i]], clear_terminals);
45584865Sobrien}
45684865Sobrien
457130561Sobrien/* Look up an instruction class; if CREATE make a new one if none found;
458130561Sobrien   returns the index into the insn class array.  */
45984865Sobrienstatic int
460130561Sobrienfetch_insn_class (const char *full_name, int create)
46184865Sobrien{
46284865Sobrien  char *name;
46384865Sobrien  char *notestr;
46484865Sobrien  char *xsect;
46584865Sobrien  char *comment;
46684865Sobrien  int i, note = 0;
46784865Sobrien  int ind;
46884865Sobrien  int is_class = 0;
46984865Sobrien
470218822Sdim  if (CONST_STRNEQ (full_name, "IC:"))
47184865Sobrien    {
47284865Sobrien      name = xstrdup (full_name + 3);
47384865Sobrien      is_class = 1;
47484865Sobrien    }
47584865Sobrien  else
47684865Sobrien    name = xstrdup (full_name);
47784865Sobrien
47884865Sobrien  if ((xsect = strchr(name, '\\')) != NULL)
47984865Sobrien    is_class = 1;
48084865Sobrien  if ((comment = strchr(name, '[')) != NULL)
48184865Sobrien    is_class = 1;
48284865Sobrien  if ((notestr = strchr(name, '+')) != NULL)
48384865Sobrien    is_class = 1;
48484865Sobrien
48584865Sobrien  /* If it is a composite class, then ignore comments and notes that come after
48684865Sobrien     the '\\', since they don't apply to the part we are decoding now.  */
48784865Sobrien  if (xsect)
48884865Sobrien    {
48984865Sobrien      if (comment > xsect)
49084865Sobrien	comment = 0;
49184865Sobrien      if (notestr > xsect)
49284865Sobrien	notestr = 0;
49384865Sobrien    }
49484865Sobrien
49584865Sobrien  if (notestr)
49684865Sobrien    {
49784865Sobrien      char *nextnotestr;
498130561Sobrien
49984865Sobrien      note = atoi (notestr + 1);
50084865Sobrien      if ((nextnotestr = strchr (notestr + 1, '+')) != NULL)
50184865Sobrien        {
50284865Sobrien          if (strcmp (notestr, "+1+13") == 0)
50384865Sobrien            note = 13;
50484865Sobrien          else if (!xsect || nextnotestr < xsect)
505130561Sobrien            warn (_("multiple note %s not handled\n"), notestr);
50684865Sobrien        }
50784865Sobrien    }
50884865Sobrien
50984865Sobrien  /* If it's a composite class, leave the notes and comments in place so that
51084865Sobrien     we have a unique name for the composite class.  Otherwise, we remove
51184865Sobrien     them.  */
51284865Sobrien  if (!xsect)
51384865Sobrien    {
51484865Sobrien      if (notestr)
51584865Sobrien        *notestr = 0;
51684865Sobrien      if (comment)
51784865Sobrien        *comment = 0;
51884865Sobrien    }
51984865Sobrien
520130561Sobrien  for (i = 0; i < iclen; i++)
521130561Sobrien    if (strcmp (name, ics[i]->name) == 0
52284865Sobrien        && ((comment == NULL && ics[i]->comment == NULL)
52384865Sobrien            || (comment != NULL && ics[i]->comment != NULL
52484865Sobrien                && strncmp (ics[i]->comment, comment,
52584865Sobrien                            strlen (ics[i]->comment)) == 0))
52684865Sobrien        && note == ics[i]->note)
52784865Sobrien      return i;
52884865Sobrien
52984865Sobrien  if (!create)
53084865Sobrien    return -1;
53184865Sobrien
532130561Sobrien  /* Doesn't exist, so make a new one.  */
53384865Sobrien  if (iclen == ictotlen)
53484865Sobrien    {
53584865Sobrien      ictotlen += 20;
53684865Sobrien      ics = (struct iclass **)
537130561Sobrien        xrealloc (ics, (ictotlen) * sizeof (struct iclass *));
53884865Sobrien    }
539130561Sobrien
54084865Sobrien  ind = iclen++;
541130561Sobrien  ics[ind] = tmalloc (struct iclass);
542130561Sobrien  memset ((void *)ics[ind], 0, sizeof (struct iclass));
543130561Sobrien  ics[ind]->name = xstrdup (name);
54484865Sobrien  ics[ind]->is_class = is_class;
54584865Sobrien  ics[ind]->orphan = 1;
54684865Sobrien
54784865Sobrien  if (comment)
54884865Sobrien    {
54984865Sobrien      ics[ind]->comment = xstrdup (comment + 1);
550130561Sobrien      ics[ind]->comment[strlen (ics[ind]->comment)-1] = 0;
55184865Sobrien    }
552130561Sobrien
55384865Sobrien  if (notestr)
55484865Sobrien    ics[ind]->note = note;
55584865Sobrien
556130561Sobrien  /* If it's a composite class, there's a comment or note, look for an
557130561Sobrien     existing class or terminal with the same name.  */
55884865Sobrien  if ((xsect || comment || notestr) && is_class)
55984865Sobrien    {
56084865Sobrien      /* First, populate with the class we're based on.  */
56184865Sobrien      char *subname = name;
562130561Sobrien
56384865Sobrien      if (xsect)
56484865Sobrien        *xsect = 0;
56584865Sobrien      else if (comment)
56684865Sobrien        *comment = 0;
56784865Sobrien      else if (notestr)
56884865Sobrien        *notestr = 0;
569130561Sobrien
57084865Sobrien      ics[ind]->nsubs = 1;
57184865Sobrien      ics[ind]->subs = tmalloc(int);
57284865Sobrien      ics[ind]->subs[0] = fetch_insn_class (subname, 1);;
57384865Sobrien    }
57484865Sobrien
57584865Sobrien  while (xsect)
57684865Sobrien    {
57784865Sobrien      char *subname = xsect + 1;
578130561Sobrien
57984865Sobrien      xsect = strchr (subname, '\\');
58084865Sobrien      if (xsect)
58184865Sobrien        *xsect = 0;
58284865Sobrien      ics[ind]->xsubs[ics[ind]->nxsubs] = fetch_insn_class (subname,1);
58384865Sobrien      ics[ind]->nxsubs++;
58484865Sobrien    }
58584865Sobrien  free (name);
58684865Sobrien
58784865Sobrien  return ind;
58884865Sobrien}
58984865Sobrien
590130561Sobrien/* For sorting a class's sub-class list only; make sure classes appear before
591130561Sobrien   terminals.  */
59284865Sobrienstatic int
59384865Sobriensub_compare (const void *e1, const void *e2)
59484865Sobrien{
59584865Sobrien  struct iclass *ic1 = ics[*(int *)e1];
59684865Sobrien  struct iclass *ic2 = ics[*(int *)e2];
59784865Sobrien
59884865Sobrien  if (ic1->is_class)
59984865Sobrien    {
60084865Sobrien      if (!ic2->is_class)
60184865Sobrien        return -1;
60284865Sobrien    }
60384865Sobrien  else if (ic2->is_class)
60484865Sobrien    return 1;
60584865Sobrien
60684865Sobrien  return strcmp (ic1->name, ic2->name);
60784865Sobrien}
60884865Sobrien
60984865Sobrienstatic void
610130561Sobrienload_insn_classes (void)
61184865Sobrien{
612130561Sobrien  FILE *fp = fopen ("ia64-ic.tbl", "r");
61384865Sobrien  char buf[2048];
61484865Sobrien
615130561Sobrien  if (fp == NULL)
616130561Sobrien    fail (_("can't find ia64-ic.tbl for reading\n"));
61784865Sobrien
618130561Sobrien  /* Discard first line.  */
61984865Sobrien  fgets (buf, sizeof(buf), fp);
62084865Sobrien
621130561Sobrien  while (!feof (fp))
62284865Sobrien    {
62384865Sobrien      int iclass;
62484865Sobrien      char *name;
62584865Sobrien      char *tmp;
62684865Sobrien
627130561Sobrien      if (fgets (buf, sizeof (buf), fp) == NULL)
62884865Sobrien        break;
62984865Sobrien
630130561Sobrien      while (ISSPACE (buf[strlen (buf) - 1]))
631130561Sobrien        buf[strlen (buf) - 1] = '\0';
63284865Sobrien
63384865Sobrien      name = tmp = buf;
63484865Sobrien      while (*tmp != ';')
63584865Sobrien        {
63684865Sobrien          ++tmp;
637130561Sobrien          if (tmp == buf + sizeof (buf))
63884865Sobrien            abort ();
63984865Sobrien        }
64084865Sobrien      *tmp++ = '\0';
64184865Sobrien
642130561Sobrien      iclass = fetch_insn_class (name, 1);
64384865Sobrien      ics[iclass]->is_class = 1;
64484865Sobrien
64584865Sobrien      if (strcmp (name, "none") == 0)
64684865Sobrien        {
64784865Sobrien          ics[iclass]->is_class = 0;
64884865Sobrien          ics[iclass]->terminal_resolved = 1;
64984865Sobrien          continue;
65084865Sobrien        }
65184865Sobrien
652130561Sobrien      /* For this class, record all sub-classes.  */
65384865Sobrien      while (*tmp)
65484865Sobrien        {
65584865Sobrien          char *subname;
65684865Sobrien          int sub;
65784865Sobrien
65889857Sobrien          while (*tmp && ISSPACE (*tmp))
65984865Sobrien            {
66084865Sobrien              ++tmp;
661130561Sobrien              if (tmp == buf + sizeof (buf))
662130561Sobrien                abort ();
66384865Sobrien            }
66484865Sobrien          subname = tmp;
66584865Sobrien          while (*tmp && *tmp != ',')
66684865Sobrien            {
66784865Sobrien              ++tmp;
668130561Sobrien              if (tmp == buf + sizeof (buf))
669130561Sobrien                abort ();
67084865Sobrien            }
67184865Sobrien          if (*tmp == ',')
67284865Sobrien            *tmp++ = '\0';
67384865Sobrien
67484865Sobrien          ics[iclass]->subs = (int *)
675130561Sobrien            xrealloc ((void *)ics[iclass]->subs,
676130561Sobrien		      (ics[iclass]->nsubs + 1) * sizeof (int));
67784865Sobrien
678130561Sobrien          sub = fetch_insn_class (subname, 1);
67984865Sobrien          ics[iclass]->subs = (int *)
680130561Sobrien            xrealloc (ics[iclass]->subs, (ics[iclass]->nsubs + 1) * sizeof (int));
68184865Sobrien          ics[iclass]->subs[ics[iclass]->nsubs++] = sub;
68284865Sobrien        }
683130561Sobrien
684130561Sobrien      /* Make sure classes come before terminals.  */
68584865Sobrien      qsort ((void *)ics[iclass]->subs,
68684865Sobrien             ics[iclass]->nsubs, sizeof(int), sub_compare);
68784865Sobrien    }
688130561Sobrien  fclose (fp);
68984865Sobrien
69084865Sobrien  if (debug)
691130561Sobrien    printf ("%d classes\n", iclen);
69284865Sobrien}
69384865Sobrien
694130561Sobrien/* Extract the insn classes from the given line.  */
69584865Sobrienstatic void
696130561Sobrienparse_resource_users (ref, usersp, nusersp, notesp)
697130561Sobrien  const char *ref;
69884865Sobrien  int **usersp;
69984865Sobrien  int *nusersp;
70084865Sobrien  int **notesp;
70184865Sobrien{
70284865Sobrien  int c;
70384865Sobrien  char *line = xstrdup (ref);
70484865Sobrien  char *tmp = line;
70584865Sobrien  int *users = *usersp;
70684865Sobrien  int count = *nusersp;
70784865Sobrien  int *notes = *notesp;
70884865Sobrien
70984865Sobrien  c = *tmp;
71084865Sobrien  while (c != 0)
71184865Sobrien    {
71284865Sobrien      char *notestr;
71384865Sobrien      int note;
71484865Sobrien      char *xsect;
71584865Sobrien      int iclass;
71684865Sobrien      int create = 0;
71784865Sobrien      char *name;
71884865Sobrien
71989857Sobrien      while (ISSPACE (*tmp))
72084865Sobrien        ++tmp;
72184865Sobrien      name = tmp;
72284865Sobrien      while (*tmp && *tmp != ',')
72384865Sobrien        ++tmp;
72484865Sobrien      c = *tmp;
72584865Sobrien      *tmp++ = '\0';
72684865Sobrien
727130561Sobrien      xsect = strchr (name, '\\');
728130561Sobrien      if ((notestr = strstr (name, "+")) != NULL)
72984865Sobrien        {
73084865Sobrien          char *nextnotestr;
731130561Sobrien
73284865Sobrien          note = atoi (notestr + 1);
73384865Sobrien          if ((nextnotestr = strchr (notestr + 1, '+')) != NULL)
73484865Sobrien            {
735130561Sobrien              /* Note 13 always implies note 1.  */
73684865Sobrien              if (strcmp (notestr, "+1+13") == 0)
73784865Sobrien                note = 13;
73884865Sobrien              else if (!xsect || nextnotestr < xsect)
739130561Sobrien                warn (_("multiple note %s not handled\n"), notestr);
74084865Sobrien            }
74184865Sobrien          if (!xsect)
74284865Sobrien            *notestr = '\0';
74384865Sobrien        }
74484865Sobrien      else
74584865Sobrien        note = 0;
746130561Sobrien
74784865Sobrien      /* All classes are created when the insn class table is parsed;
74884865Sobrien         Individual instructions might not appear until the dependency tables
74984865Sobrien         are read.  Only create new classes if it's *not* an insn class,
75084865Sobrien         or if it's a composite class (which wouldn't necessarily be in the IC
751130561Sobrien         table).  */
752218822Sdim      if (! CONST_STRNEQ (name, "IC:") || xsect != NULL)
75384865Sobrien        create = 1;
75484865Sobrien
755130561Sobrien      iclass = fetch_insn_class (name, create);
75684865Sobrien      if (iclass != -1)
75784865Sobrien        {
75884865Sobrien          users = (int *)
759130561Sobrien            xrealloc ((void *) users,(count + 1) * sizeof (int));
76084865Sobrien          notes = (int *)
761130561Sobrien            xrealloc ((void *) notes,(count + 1) * sizeof (int));
76284865Sobrien          notes[count] = note;
76384865Sobrien          users[count++] = iclass;
76484865Sobrien          mark_used (ics[iclass], 0);
76584865Sobrien        }
766130561Sobrien      else if (debug)
767130561Sobrien	printf("Class %s not found\n", name);
76884865Sobrien    }
769130561Sobrien  /* Update the return values.  */
77084865Sobrien  *usersp = users;
77184865Sobrien  *nusersp = count;
77284865Sobrien  *notesp = notes;
77384865Sobrien
77484865Sobrien  free (line);
77584865Sobrien}
77684865Sobrien
77784865Sobrienstatic int
77884865Sobrienparse_semantics (char *sem)
77984865Sobrien{
78084865Sobrien  if (strcmp (sem, "none") == 0)
78184865Sobrien    return IA64_DVS_NONE;
78284865Sobrien  else if (strcmp (sem, "implied") == 0)
78384865Sobrien    return IA64_DVS_IMPLIED;
78484865Sobrien  else if (strcmp (sem, "impliedF") == 0)
78584865Sobrien    return IA64_DVS_IMPLIEDF;
78684865Sobrien  else if (strcmp (sem, "data") == 0)
78784865Sobrien    return IA64_DVS_DATA;
78884865Sobrien  else if (strcmp (sem, "instr") == 0)
78984865Sobrien    return IA64_DVS_INSTR;
79084865Sobrien  else if (strcmp (sem, "specific") == 0)
79184865Sobrien    return IA64_DVS_SPECIFIC;
79284865Sobrien  else if (strcmp (sem, "stop") == 0)
79384865Sobrien    return IA64_DVS_STOP;
79484865Sobrien  else
79584865Sobrien    return IA64_DVS_OTHER;
79684865Sobrien}
79784865Sobrien
79884865Sobrienstatic void
79984865Sobrienadd_dep (const char *name, const char *chk, const char *reg,
80084865Sobrien         int semantics, int mode, char *extra, int flag)
80184865Sobrien{
80284865Sobrien  struct rdep *rs;
80384865Sobrien
80484865Sobrien  rs = insert_resource (name, mode);
805130561Sobrien
806130561Sobrien  parse_resource_users (chk, &rs->chks, &rs->nchks, &rs->chknotes);
807130561Sobrien  parse_resource_users (reg, &rs->regs, &rs->nregs, &rs->regnotes);
808130561Sobrien
80984865Sobrien  rs->semantics = semantics;
81084865Sobrien  rs->extra = extra;
81184865Sobrien  rs->waw_special = flag;
81284865Sobrien}
81384865Sobrien
81484865Sobrienstatic void
81584865Sobrienload_depfile (const char *filename, enum ia64_dependency_mode mode)
81684865Sobrien{
817130561Sobrien  FILE *fp = fopen (filename, "r");
81884865Sobrien  char buf[1024];
81984865Sobrien
820130561Sobrien  if (fp == NULL)
821130561Sobrien    fail (_("can't find %s for reading\n"), filename);
82284865Sobrien
823130561Sobrien  fgets (buf, sizeof(buf), fp);
824130561Sobrien  while (!feof (fp))
82584865Sobrien    {
82684865Sobrien      char *name, *tmp;
82784865Sobrien      int semantics;
82884865Sobrien      char *extra;
82984865Sobrien      char *regp, *chkp;
83084865Sobrien
83184865Sobrien      if (fgets (buf, sizeof(buf), fp) == NULL)
83284865Sobrien        break;
83384865Sobrien
834130561Sobrien      while (ISSPACE (buf[strlen (buf) - 1]))
835130561Sobrien        buf[strlen (buf) - 1] = '\0';
83684865Sobrien
83784865Sobrien      name = tmp = buf;
83884865Sobrien      while (*tmp != ';')
83984865Sobrien        ++tmp;
84084865Sobrien      *tmp++ = '\0';
84184865Sobrien
84289857Sobrien      while (ISSPACE (*tmp))
84384865Sobrien        ++tmp;
84484865Sobrien      regp = tmp;
84584865Sobrien      tmp = strchr (tmp, ';');
84684865Sobrien      if (!tmp)
84784865Sobrien        abort ();
84884865Sobrien      *tmp++ = 0;
84989857Sobrien      while (ISSPACE (*tmp))
85084865Sobrien        ++tmp;
85184865Sobrien      chkp = tmp;
85284865Sobrien      tmp = strchr (tmp, ';');
85384865Sobrien      if (!tmp)
85484865Sobrien        abort ();
85584865Sobrien      *tmp++ = 0;
85689857Sobrien      while (ISSPACE (*tmp))
85784865Sobrien        ++tmp;
85884865Sobrien      semantics = parse_semantics (tmp);
85984865Sobrien      extra = semantics == IA64_DVS_OTHER ? xstrdup (tmp) : NULL;
86084865Sobrien
86184865Sobrien      /* For WAW entries, if the chks and regs differ, we need to enter the
86284865Sobrien         entries in both positions so that the tables will be parsed properly,
863130561Sobrien         without a lot of extra work.  */
86484865Sobrien      if (mode == IA64_DV_WAW && strcmp (regp, chkp) != 0)
86584865Sobrien        {
86684865Sobrien          add_dep (name, chkp, regp, semantics, mode, extra, 0);
86784865Sobrien          add_dep (name, regp, chkp, semantics, mode, extra, 1);
86884865Sobrien        }
86984865Sobrien      else
87084865Sobrien        {
87184865Sobrien          add_dep (name, chkp, regp, semantics, mode, extra, 0);
87284865Sobrien        }
87384865Sobrien    }
874130561Sobrien  fclose (fp);
87584865Sobrien}
87684865Sobrien
87784865Sobrienstatic void
878130561Sobrienload_dependencies (void)
87984865Sobrien{
88084865Sobrien  load_depfile ("ia64-raw.tbl", IA64_DV_RAW);
88184865Sobrien  load_depfile ("ia64-waw.tbl", IA64_DV_WAW);
88284865Sobrien  load_depfile ("ia64-war.tbl", IA64_DV_WAR);
88384865Sobrien
88484865Sobrien  if (debug)
885130561Sobrien    printf ("%d RAW/WAW/WAR dependencies\n", rdepslen);
88684865Sobrien}
88784865Sobrien
888130561Sobrien/* Is the given operand an indirect register file operand?  */
88984865Sobrienstatic int
89084865Sobrienirf_operand (int op, const char *field)
89184865Sobrien{
89284865Sobrien  if (!field)
89384865Sobrien    {
89484865Sobrien      return op == IA64_OPND_RR_R3 || op == IA64_OPND_DBR_R3
89584865Sobrien        || op == IA64_OPND_IBR_R3  || op == IA64_OPND_PKR_R3
89684865Sobrien	|| op == IA64_OPND_PMC_R3  || op == IA64_OPND_PMD_R3
89784865Sobrien	|| op == IA64_OPND_MSR_R3 || op == IA64_OPND_CPUID_R3;
89884865Sobrien    }
89984865Sobrien  else
90084865Sobrien    {
90184865Sobrien      return ((op == IA64_OPND_RR_R3 && strstr (field, "rr"))
90284865Sobrien              || (op == IA64_OPND_DBR_R3 && strstr (field, "dbr"))
90384865Sobrien              || (op == IA64_OPND_IBR_R3 && strstr (field, "ibr"))
90484865Sobrien              || (op == IA64_OPND_PKR_R3 && strstr (field, "pkr"))
90584865Sobrien              || (op == IA64_OPND_PMC_R3 && strstr (field, "pmc"))
90684865Sobrien              || (op == IA64_OPND_PMD_R3 && strstr (field, "pmd"))
90784865Sobrien              || (op == IA64_OPND_MSR_R3 && strstr (field, "msr"))
90884865Sobrien              || (op == IA64_OPND_CPUID_R3 && strstr (field, "cpuid")));
90984865Sobrien    }
91084865Sobrien}
91184865Sobrien
912130561Sobrien/* Handle mov_ar, mov_br, mov_cr, mov_indirect, mov_ip, mov_pr, mov_psr, and
913130561Sobrien   mov_um insn classes.  */
91484865Sobrienstatic int
91584865Sobrienin_iclass_mov_x (struct ia64_opcode *idesc, struct iclass *ic,
91684865Sobrien                 const char *format, const char *field)
91784865Sobrien{
91884865Sobrien  int plain_mov = strcmp (idesc->name, "mov") == 0;
91984865Sobrien
92084865Sobrien  if (!format)
92184865Sobrien    return 0;
92284865Sobrien
92384865Sobrien  switch (ic->name[4])
92484865Sobrien    {
92584865Sobrien    default:
92684865Sobrien      abort ();
92784865Sobrien    case 'a':
92884865Sobrien      {
92984865Sobrien        int i = strcmp (idesc->name, "mov.i") == 0;
93084865Sobrien        int m = strcmp (idesc->name, "mov.m") == 0;
93184865Sobrien        int i2627 = i && idesc->operands[0] == IA64_OPND_AR3;
93284865Sobrien        int i28 = i && idesc->operands[1] == IA64_OPND_AR3;
93384865Sobrien        int m2930 = m && idesc->operands[0] == IA64_OPND_AR3;
93484865Sobrien        int m31 = m && idesc->operands[1] == IA64_OPND_AR3;
93584865Sobrien        int pseudo0 = plain_mov && idesc->operands[1] == IA64_OPND_AR3;
93684865Sobrien        int pseudo1 = plain_mov && idesc->operands[0] == IA64_OPND_AR3;
93784865Sobrien
93884865Sobrien        /* IC:mov ar */
93984865Sobrien        if (i2627)
94084865Sobrien          return strstr (format, "I26") || strstr (format, "I27");
94184865Sobrien        if (i28)
94284865Sobrien          return strstr (format, "I28") != NULL;
94384865Sobrien        if (m2930)
94484865Sobrien          return strstr (format, "M29") || strstr (format, "M30");
94584865Sobrien        if (m31)
94684865Sobrien          return strstr (format, "M31") != NULL;
94784865Sobrien        if (pseudo0 || pseudo1)
94884865Sobrien          return 1;
94984865Sobrien      }
95084865Sobrien      break;
95184865Sobrien    case 'b':
95284865Sobrien      {
95384865Sobrien        int i21 = idesc->operands[0] == IA64_OPND_B1;
95484865Sobrien        int i22 = plain_mov && idesc->operands[1] == IA64_OPND_B2;
95584865Sobrien        if (i22)
95684865Sobrien          return strstr (format, "I22") != NULL;
95784865Sobrien        if (i21)
95884865Sobrien          return strstr (format, "I21") != NULL;
95984865Sobrien      }
96084865Sobrien      break;
96184865Sobrien    case 'c':
96284865Sobrien      {
96384865Sobrien        int m32 = plain_mov && idesc->operands[0] == IA64_OPND_CR3;
96484865Sobrien        int m33 = plain_mov && idesc->operands[1] == IA64_OPND_CR3;
96584865Sobrien        if (m32)
96684865Sobrien          return strstr (format, "M32") != NULL;
96784865Sobrien        if (m33)
96884865Sobrien          return strstr (format, "M33") != NULL;
96984865Sobrien      }
97084865Sobrien      break;
97184865Sobrien    case 'i':
97284865Sobrien      if (ic->name[5] == 'n')
97384865Sobrien        {
97484865Sobrien          int m42 = plain_mov && irf_operand (idesc->operands[0], field);
97584865Sobrien          int m43 = plain_mov && irf_operand (idesc->operands[1], field);
97684865Sobrien          if (m42)
97784865Sobrien            return strstr (format, "M42") != NULL;
97884865Sobrien          if (m43)
97984865Sobrien            return strstr (format, "M43") != NULL;
98084865Sobrien        }
98184865Sobrien      else if (ic->name[5] == 'p')
98284865Sobrien        {
98384865Sobrien          return idesc->operands[1] == IA64_OPND_IP;
98484865Sobrien        }
98584865Sobrien      else
98684865Sobrien        abort ();
98784865Sobrien      break;
98884865Sobrien    case 'p':
98984865Sobrien      if (ic->name[5] == 'r')
99084865Sobrien        {
99184865Sobrien          int i25 = plain_mov && idesc->operands[1] == IA64_OPND_PR;
99284865Sobrien          int i23 = plain_mov && idesc->operands[0] == IA64_OPND_PR;
99384865Sobrien          int i24 = plain_mov && idesc->operands[0] == IA64_OPND_PR_ROT;
99484865Sobrien          if (i23)
99584865Sobrien            return strstr (format, "I23") != NULL;
99684865Sobrien          if (i24)
99784865Sobrien            return strstr (format, "I24") != NULL;
99884865Sobrien          if (i25)
99984865Sobrien            return strstr (format, "I25") != NULL;
100084865Sobrien        }
100184865Sobrien      else if (ic->name[5] == 's')
100284865Sobrien        {
100384865Sobrien          int m35 = plain_mov && idesc->operands[0] == IA64_OPND_PSR_L;
100484865Sobrien          int m36 = plain_mov && idesc->operands[1] == IA64_OPND_PSR;
100584865Sobrien          if (m35)
100684865Sobrien            return strstr (format, "M35") != NULL;
100784865Sobrien          if (m36)
100884865Sobrien            return strstr (format, "M36") != NULL;
100984865Sobrien        }
101084865Sobrien      else
101184865Sobrien        abort ();
101284865Sobrien      break;
101384865Sobrien    case 'u':
101484865Sobrien      {
101584865Sobrien        int m35 = plain_mov && idesc->operands[0] == IA64_OPND_PSR_UM;
101684865Sobrien        int m36 = plain_mov && idesc->operands[1] == IA64_OPND_PSR_UM;
101784865Sobrien        if (m35)
101884865Sobrien          return strstr (format, "M35") != NULL;
101984865Sobrien        if (m36)
102084865Sobrien          return strstr (format, "M36") != NULL;
102184865Sobrien      }
102284865Sobrien      break;
102384865Sobrien    }
102484865Sobrien  return 0;
102584865Sobrien}
102684865Sobrien
1027130561Sobrien/* Is the given opcode in the given insn class?  */
102884865Sobrienstatic int
1029130561Sobrienin_iclass (struct ia64_opcode *idesc, struct iclass *ic,
1030130561Sobrien	   const char *format, const char *field, int *notep)
103184865Sobrien{
103284865Sobrien  int i;
103384865Sobrien  int resolved = 0;
103484865Sobrien
103584865Sobrien  if (ic->comment)
103684865Sobrien    {
1037218822Sdim      if (CONST_STRNEQ (ic->comment, "Format"))
103884865Sobrien        {
1039130561Sobrien          /* Assume that the first format seen is the most restrictive, and
1040130561Sobrien             only keep a later one if it looks like it's more restrictive.  */
104184865Sobrien          if (format)
104284865Sobrien            {
104384865Sobrien              if (strlen (ic->comment) < strlen (format))
104484865Sobrien                {
1045130561Sobrien                  warn (_("most recent format '%s'\nappears more restrictive than '%s'\n"),
1046130561Sobrien			ic->comment, format);
104784865Sobrien                  format = ic->comment;
104884865Sobrien                }
104984865Sobrien            }
105084865Sobrien          else
105184865Sobrien            format = ic->comment;
105284865Sobrien        }
1053218822Sdim      else if (CONST_STRNEQ (ic->comment, "Field"))
105484865Sobrien        {
105584865Sobrien          if (field)
1056130561Sobrien            warn (_("overlapping field %s->%s\n"),
1057130561Sobrien		  ic->comment, field);
105884865Sobrien          field = ic->comment;
105984865Sobrien        }
106084865Sobrien    }
106184865Sobrien
1062130561Sobrien  /* An insn class matches anything that is the same followed by completers,
106384865Sobrien     except when the absence and presence of completers constitutes different
1064130561Sobrien     instructions.  */
106584865Sobrien  if (ic->nsubs == 0 && ic->nxsubs == 0)
106684865Sobrien    {
1067218822Sdim      int is_mov = CONST_STRNEQ (idesc->name, "mov");
106884865Sobrien      int plain_mov = strcmp (idesc->name, "mov") == 0;
106984865Sobrien      int len = strlen(ic->name);
107084865Sobrien
107184865Sobrien      resolved = ((strncmp (ic->name, idesc->name, len) == 0)
107284865Sobrien                  && (idesc->name[len] == '\0'
107384865Sobrien                      || idesc->name[len] == '.'));
107484865Sobrien
1075130561Sobrien      /* All break, nop, and hint variations must match exactly.  */
107684865Sobrien      if (resolved &&
107784865Sobrien          (strcmp (ic->name, "break") == 0
1078130561Sobrien           || strcmp (ic->name, "nop") == 0
1079130561Sobrien	   || strcmp (ic->name, "hint") == 0))
108084865Sobrien        resolved = strcmp (ic->name, idesc->name) == 0;
108184865Sobrien
1082130561Sobrien      /* Assume restrictions in the FORMAT/FIELD negate resolution,
1083130561Sobrien         unless specifically allowed by clauses in this block.  */
108484865Sobrien      if (resolved && field)
108584865Sobrien        {
1086130561Sobrien          /* Check Field(sf)==sN against opcode sN.  */
108784865Sobrien          if (strstr(field, "(sf)==") != NULL)
108884865Sobrien            {
108984865Sobrien              char *sf;
1090130561Sobrien
109184865Sobrien              if ((sf = strstr (idesc->name, ".s")) != 0)
1092130561Sobrien		resolved = strcmp (sf + 1, strstr (field, "==") + 2) == 0;
109384865Sobrien            }
1094130561Sobrien          /* Check Field(lftype)==XXX.  */
109584865Sobrien          else if (strstr (field, "(lftype)") != NULL)
109684865Sobrien            {
109784865Sobrien              if (strstr (idesc->name, "fault") != NULL)
109884865Sobrien                resolved = strstr (field, "fault") != NULL;
109984865Sobrien              else
110084865Sobrien                resolved = strstr (field, "fault") == NULL;
110184865Sobrien            }
1102130561Sobrien          /* Handle Field(ctype)==XXX.  */
110384865Sobrien          else if (strstr (field, "(ctype)") != NULL)
110484865Sobrien            {
110584865Sobrien              if (strstr (idesc->name, "or.andcm"))
110684865Sobrien                resolved = strstr (field, "or.andcm") != NULL;
110784865Sobrien              else if (strstr (idesc->name, "and.orcm"))
110884865Sobrien                resolved = strstr (field, "and.orcm") != NULL;
110984865Sobrien              else if (strstr (idesc->name, "orcm"))
111084865Sobrien                resolved = strstr (field, "or orcm") != NULL;
111184865Sobrien              else if (strstr (idesc->name, "or"))
111284865Sobrien                resolved = strstr (field, "or orcm") != NULL;
111384865Sobrien              else if (strstr (idesc->name, "andcm"))
111484865Sobrien                resolved = strstr (field, "and andcm") != NULL;
111584865Sobrien              else if (strstr (idesc->name, "and"))
111684865Sobrien                resolved = strstr (field, "and andcm") != NULL;
111784865Sobrien              else if (strstr (idesc->name, "unc"))
111884865Sobrien                resolved = strstr (field, "unc") != NULL;
111984865Sobrien              else
112084865Sobrien                resolved = strcmp (field, "Field(ctype)==") == 0;
112184865Sobrien            }
112284865Sobrien        }
1123130561Sobrien
112484865Sobrien      if (resolved && format)
112584865Sobrien        {
1126218822Sdim          if (CONST_STRNEQ (idesc->name, "dep")
112784865Sobrien                   && strstr (format, "I13") != NULL)
112884865Sobrien            resolved = idesc->operands[1] == IA64_OPND_IMM8;
1129218822Sdim          else if (CONST_STRNEQ (idesc->name, "chk")
113084865Sobrien                   && strstr (format, "M21") != NULL)
113184865Sobrien            resolved = idesc->operands[0] == IA64_OPND_F2;
1132218822Sdim          else if (CONST_STRNEQ (idesc->name, "lfetch"))
113384865Sobrien            resolved = (strstr (format, "M14 M15") != NULL
113484865Sobrien                        && (idesc->operands[1] == IA64_OPND_R2
113584865Sobrien                            || idesc->operands[1] == IA64_OPND_IMM9b));
1136218822Sdim          else if (CONST_STRNEQ (idesc->name, "br.call")
113784865Sobrien                   && strstr (format, "B5") != NULL)
113884865Sobrien            resolved = idesc->operands[1] == IA64_OPND_B2;
1139218822Sdim          else if (CONST_STRNEQ (idesc->name, "br.call")
114084865Sobrien                   && strstr (format, "B3") != NULL)
114184865Sobrien            resolved = idesc->operands[1] == IA64_OPND_TGT25c;
1142218822Sdim          else if (CONST_STRNEQ (idesc->name, "brp")
114384865Sobrien                   && strstr (format, "B7") != NULL)
114484865Sobrien            resolved = idesc->operands[0] == IA64_OPND_B2;
114584865Sobrien          else if (strcmp (ic->name, "invala") == 0)
114684865Sobrien            resolved = strcmp (idesc->name, ic->name) == 0;
1147218822Sdim	  else if (CONST_STRNEQ (idesc->name, "st")
1148218822Sdim		   && (strstr (format, "M5") != NULL
1149218822Sdim		       || strstr (format, "M10") != NULL))
115084865Sobrien	    resolved = idesc->flags & IA64_OPCODE_POSTINC;
1151218822Sdim	  else if (CONST_STRNEQ (idesc->name, "ld")
1152218822Sdim		   && (strstr (format, "M2 M3") != NULL
1153218822Sdim		       || strstr (format, "M12") != NULL
1154218822Sdim		       || strstr (format, "M7 M8") != NULL))
1155218822Sdim	    resolved = idesc->flags & IA64_OPCODE_POSTINC;
115684865Sobrien          else
115784865Sobrien            resolved = 0;
115884865Sobrien        }
115984865Sobrien
1160130561Sobrien      /* Misc brl variations ('.cond' is optional);
1161130561Sobrien         plain brl matches brl.cond.  */
116284865Sobrien      if (!resolved
116384865Sobrien          && (strcmp (idesc->name, "brl") == 0
1164218822Sdim              || CONST_STRNEQ (idesc->name, "brl."))
116584865Sobrien          && strcmp (ic->name, "brl.cond") == 0)
116684865Sobrien        {
116784865Sobrien          resolved = 1;
116884865Sobrien        }
116984865Sobrien
1170130561Sobrien      /* Misc br variations ('.cond' is optional).  */
117184865Sobrien      if (!resolved
117284865Sobrien          && (strcmp (idesc->name, "br") == 0
1173218822Sdim              || CONST_STRNEQ (idesc->name, "br."))
117484865Sobrien          && strcmp (ic->name, "br.cond") == 0)
117584865Sobrien        {
117684865Sobrien          if (format)
117784865Sobrien            resolved = (strstr (format, "B4") != NULL
117884865Sobrien                        && idesc->operands[0] == IA64_OPND_B2)
117984865Sobrien              || (strstr (format, "B1") != NULL
118084865Sobrien                  && idesc->operands[0] == IA64_OPND_TGT25c);
118184865Sobrien          else
118284865Sobrien            resolved = 1;
118384865Sobrien        }
118484865Sobrien
1185130561Sobrien      /* probe variations.  */
1186218822Sdim      if (!resolved && CONST_STRNEQ (idesc->name, "probe"))
118784865Sobrien        {
118884865Sobrien          resolved = strcmp (ic->name, "probe") == 0
118984865Sobrien            && !((strstr (idesc->name, "fault") != NULL)
119084865Sobrien                 ^ (format && strstr (format, "M40") != NULL));
119184865Sobrien        }
1192130561Sobrien
1193130561Sobrien      /* mov variations.  */
119484865Sobrien      if (!resolved && is_mov)
119584865Sobrien        {
119684865Sobrien          if (plain_mov)
119784865Sobrien            {
1198130561Sobrien              /* mov alias for fmerge.  */
119984865Sobrien              if (strcmp (ic->name, "fmerge") == 0)
120084865Sobrien                {
120184865Sobrien                  resolved = idesc->operands[0] == IA64_OPND_F1
120284865Sobrien                    && idesc->operands[1] == IA64_OPND_F3;
120384865Sobrien                }
1204130561Sobrien              /* mov alias for adds (r3 or imm14).  */
120584865Sobrien              else if (strcmp (ic->name, "adds") == 0)
120684865Sobrien                {
120784865Sobrien                  resolved = (idesc->operands[0] == IA64_OPND_R1
120884865Sobrien                              && (idesc->operands[1] == IA64_OPND_R3
120984865Sobrien                                  || (idesc->operands[1] == IA64_OPND_IMM14)));
121084865Sobrien                }
1211130561Sobrien              /* mov alias for addl.  */
121284865Sobrien              else if (strcmp (ic->name, "addl") == 0)
121384865Sobrien                {
121484865Sobrien                  resolved = idesc->operands[0] == IA64_OPND_R1
121584865Sobrien                    && idesc->operands[1] == IA64_OPND_IMM22;
121684865Sobrien                }
121784865Sobrien            }
1218130561Sobrien
1219130561Sobrien          /* Some variants of mov and mov.[im].  */
1220218822Sdim          if (!resolved && CONST_STRNEQ (ic->name, "mov_"))
1221130561Sobrien	    resolved = in_iclass_mov_x (idesc, ic, format, field);
122284865Sobrien        }
122384865Sobrien
1224130561Sobrien      /* Keep track of this so we can flag any insn classes which aren't
1225130561Sobrien         mapped onto at least one real insn.  */
122684865Sobrien      if (resolved)
1227130561Sobrien	ic->terminal_resolved = 1;
122884865Sobrien    }
1229130561Sobrien  else for (i = 0; i < ic->nsubs; i++)
123084865Sobrien    {
1231130561Sobrien      if (in_iclass (idesc, ics[ic->subs[i]], format, field, notep))
123284865Sobrien        {
123384865Sobrien          int j;
1234130561Sobrien
1235130561Sobrien          for (j = 0; j < ic->nxsubs; j++)
1236130561Sobrien	    if (in_iclass (idesc, ics[ic->xsubs[j]], NULL, NULL, NULL))
1237130561Sobrien	      return 0;
1238130561Sobrien
123984865Sobrien          if (debug > 1)
1240130561Sobrien            printf ("%s is in IC %s\n", idesc->name, ic->name);
1241130561Sobrien
124284865Sobrien          resolved = 1;
124384865Sobrien          break;
124484865Sobrien        }
124584865Sobrien    }
124684865Sobrien
1247130561Sobrien  /* If it's in this IC, add the IC note (if any) to the insn.  */
124884865Sobrien  if (resolved)
124984865Sobrien    {
125084865Sobrien      if (ic->note && notep)
125184865Sobrien        {
125284865Sobrien          if (*notep && *notep != ic->note)
1253130561Sobrien	    warn (_("overwriting note %d with note %d (IC:%s)\n"),
1254130561Sobrien		  *notep, ic->note, ic->name);
1255130561Sobrien
125684865Sobrien          *notep = ic->note;
125784865Sobrien        }
125884865Sobrien    }
125984865Sobrien
126084865Sobrien  return resolved;
126184865Sobrien}
126284865Sobrien
126384865Sobrien
126484865Sobrienstatic int
126584865Sobrienlookup_regindex (const char *name, int specifier)
126684865Sobrien{
126784865Sobrien  switch (specifier)
126884865Sobrien    {
126984865Sobrien    case IA64_RS_ARX:
127084865Sobrien      if (strstr (name, "[RSC]"))
127184865Sobrien        return 16;
127284865Sobrien      if (strstr (name, "[BSP]"))
127384865Sobrien        return 17;
127484865Sobrien      else if (strstr (name, "[BSPSTORE]"))
127584865Sobrien        return 18;
127684865Sobrien      else if (strstr (name, "[RNAT]"))
127784865Sobrien        return 19;
1278130561Sobrien      else if (strstr (name, "[FCR]"))
1279130561Sobrien        return 21;
1280130561Sobrien      else if (strstr (name, "[EFLAG]"))
1281130561Sobrien        return 24;
1282130561Sobrien      else if (strstr (name, "[CSD]"))
1283130561Sobrien        return 25;
1284130561Sobrien      else if (strstr (name, "[SSD]"))
1285130561Sobrien        return 26;
1286130561Sobrien      else if (strstr (name, "[CFLG]"))
1287130561Sobrien        return 27;
1288130561Sobrien      else if (strstr (name, "[FSR]"))
1289130561Sobrien        return 28;
1290130561Sobrien      else if (strstr (name, "[FIR]"))
1291130561Sobrien        return 29;
1292130561Sobrien      else if (strstr (name, "[FDR]"))
1293130561Sobrien        return 30;
129484865Sobrien      else if (strstr (name, "[CCV]"))
129584865Sobrien        return 32;
129684865Sobrien      else if (strstr (name, "[ITC]"))
129784865Sobrien        return 44;
129884865Sobrien      else if (strstr (name, "[PFS]"))
129984865Sobrien        return 64;
130084865Sobrien      else if (strstr (name, "[LC]"))
130184865Sobrien        return 65;
130284865Sobrien      else if (strstr (name, "[EC]"))
130384865Sobrien        return 66;
130484865Sobrien      abort ();
130584865Sobrien    case IA64_RS_CRX:
130684865Sobrien      if (strstr (name, "[DCR]"))
130784865Sobrien        return 0;
130884865Sobrien      else if (strstr (name, "[ITM]"))
130984865Sobrien        return 1;
131084865Sobrien      else if (strstr (name, "[IVA]"))
131184865Sobrien        return 2;
131284865Sobrien      else if (strstr (name, "[PTA]"))
131384865Sobrien        return 8;
131484865Sobrien      else if (strstr (name, "[GPTA]"))
131584865Sobrien        return 9;
131684865Sobrien      else if (strstr (name, "[IPSR]"))
131784865Sobrien        return 16;
131884865Sobrien      else if (strstr (name, "[ISR]"))
131984865Sobrien        return 17;
132084865Sobrien      else if (strstr (name, "[IIP]"))
132184865Sobrien        return 19;
132284865Sobrien      else if (strstr (name, "[IFA]"))
132384865Sobrien        return 20;
132484865Sobrien      else if (strstr (name, "[ITIR]"))
132584865Sobrien        return 21;
132684865Sobrien      else if (strstr (name, "[IIPA]"))
132784865Sobrien        return 22;
132884865Sobrien      else if (strstr (name, "[IFS]"))
132984865Sobrien        return 23;
133084865Sobrien      else if (strstr (name, "[IIM]"))
133184865Sobrien        return 24;
133284865Sobrien      else if (strstr (name, "[IHA]"))
133384865Sobrien        return 25;
133484865Sobrien      else if (strstr (name, "[LID]"))
133584865Sobrien        return 64;
133684865Sobrien      else if (strstr (name, "[IVR]"))
133784865Sobrien        return 65;
133884865Sobrien      else if (strstr (name, "[TPR]"))
133984865Sobrien        return 66;
134084865Sobrien      else if (strstr (name, "[EOI]"))
134184865Sobrien        return 67;
134284865Sobrien      else if (strstr (name, "[ITV]"))
134384865Sobrien        return 72;
134484865Sobrien      else if (strstr (name, "[PMV]"))
134584865Sobrien        return 73;
134684865Sobrien      else if (strstr (name, "[CMCV]"))
134784865Sobrien        return 74;
134884865Sobrien      abort ();
134984865Sobrien    case IA64_RS_PSR:
135084865Sobrien      if (strstr (name, ".be"))
135184865Sobrien        return 1;
135284865Sobrien      else if (strstr (name, ".up"))
135384865Sobrien        return 2;
135484865Sobrien      else if (strstr (name, ".ac"))
135584865Sobrien        return 3;
135684865Sobrien      else if (strstr (name, ".mfl"))
135784865Sobrien        return 4;
135884865Sobrien      else if (strstr (name, ".mfh"))
135984865Sobrien        return 5;
136084865Sobrien      else if (strstr (name, ".ic"))
136184865Sobrien        return 13;
136284865Sobrien      else if (strstr (name, ".i"))
136384865Sobrien        return 14;
136484865Sobrien      else if (strstr (name, ".pk"))
136584865Sobrien        return 15;
136684865Sobrien      else if (strstr (name, ".dt"))
136784865Sobrien        return 17;
136884865Sobrien      else if (strstr (name, ".dfl"))
136984865Sobrien        return 18;
137084865Sobrien      else if (strstr (name, ".dfh"))
137184865Sobrien        return 19;
137284865Sobrien      else if (strstr (name, ".sp"))
137384865Sobrien        return 20;
137484865Sobrien      else if (strstr (name, ".pp"))
137584865Sobrien        return 21;
137684865Sobrien      else if (strstr (name, ".di"))
137784865Sobrien        return 22;
137884865Sobrien      else if (strstr (name, ".si"))
137984865Sobrien        return 23;
138084865Sobrien      else if (strstr (name, ".db"))
138184865Sobrien        return 24;
138284865Sobrien      else if (strstr (name, ".lp"))
138384865Sobrien        return 25;
138484865Sobrien      else if (strstr (name, ".tb"))
138584865Sobrien        return 26;
138684865Sobrien      else if (strstr (name, ".rt"))
138784865Sobrien        return 27;
138884865Sobrien      else if (strstr (name, ".cpl"))
138984865Sobrien        return 32;
139084865Sobrien      else if (strstr (name, ".rs"))
139184865Sobrien        return 34;
139284865Sobrien      else if (strstr (name, ".mc"))
139384865Sobrien        return 35;
139484865Sobrien      else if (strstr (name, ".it"))
139584865Sobrien        return 36;
139684865Sobrien      else if (strstr (name, ".id"))
139784865Sobrien        return 37;
139884865Sobrien      else if (strstr (name, ".da"))
139984865Sobrien        return 38;
140084865Sobrien      else if (strstr (name, ".dd"))
140184865Sobrien        return 39;
140284865Sobrien      else if (strstr (name, ".ss"))
140384865Sobrien        return 40;
140484865Sobrien      else if (strstr (name, ".ri"))
140584865Sobrien        return 41;
140684865Sobrien      else if (strstr (name, ".ed"))
140784865Sobrien        return 43;
140884865Sobrien      else if (strstr (name, ".bn"))
140984865Sobrien        return 44;
141084865Sobrien      else if (strstr (name, ".ia"))
141184865Sobrien        return 45;
1412218822Sdim      else if (strstr (name, ".vm"))
1413218822Sdim        return 46;
141484865Sobrien      else
141584865Sobrien        abort ();
141684865Sobrien    default:
141784865Sobrien      break;
141884865Sobrien    }
141984865Sobrien  return REG_NONE;
142084865Sobrien}
142184865Sobrien
142284865Sobrienstatic int
142384865Sobrienlookup_specifier (const char *name)
142484865Sobrien{
142584865Sobrien  if (strchr (name, '%'))
142684865Sobrien    {
142784865Sobrien      if (strstr (name, "AR[K%]") != NULL)
142884865Sobrien        return IA64_RS_AR_K;
142984865Sobrien      if (strstr (name, "AR[UNAT]") != NULL)
143084865Sobrien        return IA64_RS_AR_UNAT;
143184865Sobrien      if (strstr (name, "AR%, % in 8") != NULL)
143284865Sobrien        return IA64_RS_AR;
143384865Sobrien      if (strstr (name, "AR%, % in 48") != NULL)
143484865Sobrien        return IA64_RS_ARb;
143584865Sobrien      if (strstr (name, "BR%") != NULL)
143684865Sobrien        return IA64_RS_BR;
143784865Sobrien      if (strstr (name, "CR[IRR%]") != NULL)
143884865Sobrien        return IA64_RS_CR_IRR;
143984865Sobrien      if (strstr (name, "CR[LRR%]") != NULL)
144084865Sobrien        return IA64_RS_CR_LRR;
144184865Sobrien      if (strstr (name, "CR%") != NULL)
144284865Sobrien        return IA64_RS_CR;
144384865Sobrien      if (strstr (name, "FR%, % in 0") != NULL)
144484865Sobrien        return IA64_RS_FR;
144584865Sobrien      if (strstr (name, "FR%, % in 2") != NULL)
144684865Sobrien        return IA64_RS_FRb;
144784865Sobrien      if (strstr (name, "GR%") != NULL)
144884865Sobrien        return IA64_RS_GR;
144984865Sobrien      if (strstr (name, "PR%, % in 1 ") != NULL)
145084865Sobrien        return IA64_RS_PR;
145184865Sobrien      if (strstr (name, "PR%, % in 16 ") != NULL)
145284865Sobrien	return IA64_RS_PRr;
145384865Sobrien
1454130561Sobrien      warn (_("don't know how to specify %% dependency %s\n"),
1455130561Sobrien	    name);
145684865Sobrien    }
145784865Sobrien  else if (strchr (name, '#'))
145884865Sobrien    {
145984865Sobrien      if (strstr (name, "CPUID#") != NULL)
146084865Sobrien        return IA64_RS_CPUID;
146184865Sobrien      if (strstr (name, "DBR#") != NULL)
146284865Sobrien        return IA64_RS_DBR;
146384865Sobrien      if (strstr (name, "IBR#") != NULL)
146484865Sobrien        return IA64_RS_IBR;
146584865Sobrien      if (strstr (name, "MSR#") != NULL)
146684865Sobrien	return IA64_RS_MSR;
146784865Sobrien      if (strstr (name, "PKR#") != NULL)
146884865Sobrien        return IA64_RS_PKR;
146984865Sobrien      if (strstr (name, "PMC#") != NULL)
147084865Sobrien        return IA64_RS_PMC;
147184865Sobrien      if (strstr (name, "PMD#") != NULL)
147284865Sobrien        return IA64_RS_PMD;
147384865Sobrien      if (strstr (name, "RR#") != NULL)
147484865Sobrien        return IA64_RS_RR;
147584865Sobrien
1476130561Sobrien      warn (_("Don't know how to specify # dependency %s\n"),
1477130561Sobrien	    name);
147884865Sobrien    }
1479218822Sdim  else if (CONST_STRNEQ (name, "AR[FPSR]"))
148084865Sobrien    return IA64_RS_AR_FPSR;
1481218822Sdim  else if (CONST_STRNEQ (name, "AR["))
148284865Sobrien    return IA64_RS_ARX;
1483218822Sdim  else if (CONST_STRNEQ (name, "CR["))
148484865Sobrien    return IA64_RS_CRX;
1485218822Sdim  else if (CONST_STRNEQ (name, "PSR."))
148684865Sobrien    return IA64_RS_PSR;
148784865Sobrien  else if (strcmp (name, "InService*") == 0)
148884865Sobrien    return IA64_RS_INSERVICE;
148984865Sobrien  else if (strcmp (name, "GR0") == 0)
149084865Sobrien    return IA64_RS_GR0;
149184865Sobrien  else if (strcmp (name, "CFM") == 0)
149284865Sobrien    return IA64_RS_CFM;
149384865Sobrien  else if (strcmp (name, "PR63") == 0)
149484865Sobrien    return IA64_RS_PR63;
149584865Sobrien  else if (strcmp (name, "RSE") == 0)
149684865Sobrien    return IA64_RS_RSE;
149784865Sobrien
149884865Sobrien  return IA64_RS_ANY;
149984865Sobrien}
150084865Sobrien
1501130561Sobrienstatic void
150284865Sobrienprint_dependency_table ()
150384865Sobrien{
150484865Sobrien  int i, j;
150584865Sobrien
150684865Sobrien  if (debug)
150784865Sobrien    {
150884865Sobrien      for (i=0;i < iclen;i++)
150984865Sobrien        {
151084865Sobrien          if (ics[i]->is_class)
151184865Sobrien            {
151284865Sobrien              if (!ics[i]->nsubs)
151384865Sobrien                {
151484865Sobrien                  if (ics[i]->comment)
1515130561Sobrien		    warn (_("IC:%s [%s] has no terminals or sub-classes\n"),
1516130561Sobrien			  ics[i]->name, ics[i]->comment);
1517130561Sobrien		  else
1518130561Sobrien		    warn (_("IC:%s has no terminals or sub-classes\n"),
1519130561Sobrien			  ics[i]->name);
152084865Sobrien                }
152184865Sobrien            }
152284865Sobrien          else
152384865Sobrien            {
152484865Sobrien              if (!ics[i]->terminal_resolved && !ics[i]->orphan)
152584865Sobrien                {
152684865Sobrien                  if (ics[i]->comment)
1527130561Sobrien		    warn (_("no insns mapped directly to terminal IC %s [%s]"),
1528130561Sobrien			  ics[i]->name, ics[i]->comment);
1529130561Sobrien		  else
1530130561Sobrien		    warn (_("no insns mapped directly to terminal IC %s\n"),
1531130561Sobrien			  ics[i]->name);
153284865Sobrien                }
153384865Sobrien            }
153484865Sobrien        }
153584865Sobrien
1536130561Sobrien      for (i = 0; i < iclen; i++)
153784865Sobrien        {
153884865Sobrien          if (ics[i]->orphan)
153984865Sobrien            {
154084865Sobrien              mark_used (ics[i], 1);
1541130561Sobrien              warn (_("class %s is defined but not used\n"),
1542130561Sobrien		    ics[i]->name);
154384865Sobrien            }
154484865Sobrien        }
154584865Sobrien
1546130561Sobrien      if (debug > 1)
1547130561Sobrien	for (i = 0; i < rdepslen; i++)
1548130561Sobrien	  {
1549130561Sobrien	    static const char *mode_str[] = { "RAW", "WAW", "WAR" };
1550130561Sobrien
1551130561Sobrien	    if (rdeps[i]->total_chks == 0)
1552130561Sobrien	      warn (_("Warning: rsrc %s (%s) has no chks%s\n"),
1553130561Sobrien		    rdeps[i]->name, mode_str[rdeps[i]->mode],
1554130561Sobrien		    rdeps[i]->total_regs ? "" : " or regs");
1555130561Sobrien	    else if (rdeps[i]->total_regs == 0)
1556130561Sobrien	      warn (_("rsrc %s (%s) has no regs\n"),
1557130561Sobrien		    rdeps[i]->name, mode_str[rdeps[i]->mode]);
1558130561Sobrien	  }
155984865Sobrien    }
156084865Sobrien
1561130561Sobrien  /* The dependencies themselves.  */
156284865Sobrien  printf ("static const struct ia64_dependency\ndependencies[] = {\n");
1563130561Sobrien  for (i = 0; i < rdepslen; i++)
156484865Sobrien    {
156584865Sobrien      /* '%', '#', AR[], CR[], or PSR. indicates we need to specify the actual
1566130561Sobrien         resource used.  */
156784865Sobrien      int specifier = lookup_specifier (rdeps[i]->name);
156884865Sobrien      int regindex = lookup_regindex (rdeps[i]->name, specifier);
156984865Sobrien
157084865Sobrien      printf ("  { \"%s\", %d, %d, %d, %d, ",
157184865Sobrien              rdeps[i]->name, specifier,
157284865Sobrien              (int)rdeps[i]->mode, (int)rdeps[i]->semantics, regindex);
157384865Sobrien      if (rdeps[i]->semantics == IA64_DVS_OTHER)
1574218822Sdim	{
1575218822Sdim	  const char *quote, *rest;
1576218822Sdim
1577218822Sdim	  putchar ('\"');
1578218822Sdim	  rest = rdeps[i]->extra;
1579218822Sdim	  quote = strchr (rest, '\"');
1580218822Sdim	  while (quote != NULL)
1581218822Sdim	    {
1582218822Sdim	      printf ("%.*s\\\"", (int) (quote - rest), rest);
1583218822Sdim	      rest = quote + 1;
1584218822Sdim	      quote = strchr (rest, '\"');
1585218822Sdim	    }
1586218822Sdim	  printf ("%s\", ", rest);
1587218822Sdim	}
158884865Sobrien      else
158984865Sobrien	printf ("NULL, ");
159084865Sobrien      printf("},\n");
159184865Sobrien    }
159284865Sobrien  printf ("};\n\n");
159384865Sobrien
1594130561Sobrien  /* And dependency lists.  */
159584865Sobrien  for (i=0;i < dlistlen;i++)
159684865Sobrien    {
159784865Sobrien      int len = 2;
1598218822Sdim      printf ("static const unsigned short dep%d[] = {\n  ", i);
159984865Sobrien      for (j=0;j < dlists[i]->len; j++)
160084865Sobrien        {
160184865Sobrien          len += printf ("%d, ", dlists[i]->deps[j]);
160284865Sobrien          if (len > 75)
160384865Sobrien            {
160484865Sobrien              printf("\n  ");
160584865Sobrien              len = 2;
160684865Sobrien            }
160784865Sobrien        }
160884865Sobrien      printf ("\n};\n\n");
160984865Sobrien    }
161084865Sobrien
1611130561Sobrien  /* And opcode dependency list.  */
161284865Sobrien  printf ("#define NELS(X) (sizeof(X)/sizeof(X[0]))\n");
161384865Sobrien  printf ("static const struct ia64_opcode_dependency\n");
161484865Sobrien  printf ("op_dependencies[] = {\n");
1615130561Sobrien  for (i = 0; i < opdeplen; i++)
161684865Sobrien    {
161784865Sobrien      printf ("  { ");
161884865Sobrien      if (opdeps[i]->chk == -1)
161984865Sobrien        printf ("0, NULL, ");
162084865Sobrien      else
162184865Sobrien        printf ("NELS(dep%d), dep%d, ", opdeps[i]->chk, opdeps[i]->chk);
162284865Sobrien      if (opdeps[i]->reg == -1)
162384865Sobrien        printf ("0, NULL, ");
162484865Sobrien      else
162584865Sobrien        printf ("NELS(dep%d), dep%d, ", opdeps[i]->reg, opdeps[i]->reg);
162684865Sobrien      printf ("},\n");
162784865Sobrien    }
162884865Sobrien  printf ("};\n\n");
162984865Sobrien}
163084865Sobrien
163184865Sobrien
1632130561Sobrien/* Add STR to the string table.  */
163384865Sobrienstatic struct string_entry *
1634130561Sobrieninsert_string (char *str)
163584865Sobrien{
163684865Sobrien  int start = 0, end = strtablen;
163784865Sobrien  int i, x;
163884865Sobrien
163984865Sobrien  if (strtablen == strtabtotlen)
164084865Sobrien    {
164184865Sobrien      strtabtotlen += 20;
164284865Sobrien      string_table = (struct string_entry **)
164384865Sobrien	xrealloc (string_table,
164484865Sobrien		  sizeof (struct string_entry **) * strtabtotlen);
164584865Sobrien    }
164684865Sobrien
164784865Sobrien  if (strtablen == 0)
164884865Sobrien    {
164984865Sobrien      strtablen = 1;
165084865Sobrien      string_table[0] = tmalloc (struct string_entry);
165184865Sobrien      string_table[0]->s = xstrdup (str);
165284865Sobrien      string_table[0]->num = 0;
165384865Sobrien      return string_table[0];
165484865Sobrien    }
165584865Sobrien
165684865Sobrien  if (strcmp (str, string_table[strtablen - 1]->s) > 0)
1657130561Sobrien    i = end;
165884865Sobrien  else if (strcmp (str, string_table[0]->s) < 0)
1659130561Sobrien    i = 0;
166084865Sobrien  else
166184865Sobrien    {
166284865Sobrien      while (1)
166384865Sobrien	{
166484865Sobrien	  int c;
166584865Sobrien
166684865Sobrien	  i = (start + end) / 2;
166784865Sobrien	  c = strcmp (str, string_table[i]->s);
1668130561Sobrien
166984865Sobrien	  if (c < 0)
1670130561Sobrien	    end = i - 1;
167184865Sobrien	  else if (c == 0)
1672130561Sobrien	    return string_table[i];
167384865Sobrien	  else
1674130561Sobrien	    start = i + 1;
1675130561Sobrien
167684865Sobrien	  if (start > end)
1677130561Sobrien	    break;
167884865Sobrien	}
167984865Sobrien    }
1680130561Sobrien
168184865Sobrien  for (; i > 0 && i < strtablen; i--)
1682130561Sobrien    if (strcmp (str, string_table[i - 1]->s) > 0)
1683130561Sobrien      break;
1684130561Sobrien
168584865Sobrien  for (; i < strtablen; i++)
1686130561Sobrien    if (strcmp (str, string_table[i]->s) < 0)
1687130561Sobrien      break;
1688130561Sobrien
168984865Sobrien  for (x = strtablen - 1; x >= i; x--)
169084865Sobrien    {
169184865Sobrien      string_table[x + 1] = string_table[x];
169284865Sobrien      string_table[x + 1]->num = x + 1;
169384865Sobrien    }
1694130561Sobrien
169584865Sobrien  string_table[i] = tmalloc (struct string_entry);
169684865Sobrien  string_table[i]->s = xstrdup (str);
169784865Sobrien  string_table[i]->num = i;
169884865Sobrien  strtablen++;
1699130561Sobrien
170084865Sobrien  return string_table[i];
170184865Sobrien}
170284865Sobrien
1703130561Sobrienstatic struct bittree *
1704130561Sobrienmake_bittree_entry (void)
170584865Sobrien{
170684865Sobrien  struct bittree *res = tmalloc (struct bittree);
170784865Sobrien
170884865Sobrien  res->disent = NULL;
170984865Sobrien  res->bits[0] = NULL;
171084865Sobrien  res->bits[1] = NULL;
171184865Sobrien  res->bits[2] = NULL;
171284865Sobrien  res->skip_flag = 0;
171384865Sobrien  res->bits_to_skip = 0;
171484865Sobrien  return res;
171584865Sobrien}
1716130561Sobrien
171784865Sobrien
1718130561Sobrienstatic struct disent *
171984865Sobrienadd_dis_table_ent (which, insn, order, completer_index)
172084865Sobrien     struct disent *which;
172184865Sobrien     int insn;
172284865Sobrien     int order;
172384865Sobrien     int completer_index;
172484865Sobrien{
172584865Sobrien  int ci = 0;
172684865Sobrien  struct disent *ent;
172784865Sobrien
172884865Sobrien  if (which != NULL)
172984865Sobrien    {
173084865Sobrien      ent = which;
173184865Sobrien
173284865Sobrien      ent->nextcnt++;
173384865Sobrien      while (ent->nexte != NULL)
1734130561Sobrien	ent = ent->nexte;
1735130561Sobrien
173684865Sobrien      ent = (ent->nexte = tmalloc (struct disent));
173784865Sobrien    }
173884865Sobrien  else
173984865Sobrien    {
174084865Sobrien      ent = tmalloc (struct disent);
174184865Sobrien      ent->next_ent = disinsntable;
174284865Sobrien      disinsntable = ent;
174384865Sobrien      which = ent;
174484865Sobrien    }
174584865Sobrien  ent->nextcnt = 0;
174684865Sobrien  ent->nexte = NULL;
174784865Sobrien  ent->insn = insn;
174884865Sobrien  ent->priority = order;
174984865Sobrien
175084865Sobrien  while (completer_index != 1)
175184865Sobrien    {
175284865Sobrien      ci = (ci << 1) | (completer_index & 1);
175384865Sobrien      completer_index >>= 1;
175484865Sobrien    }
175584865Sobrien  ent->completer_index = ci;
175684865Sobrien  return which;
175784865Sobrien}
175884865Sobrien
1759130561Sobrienstatic void
176084865Sobrienfinish_distable ()
176184865Sobrien{
176284865Sobrien  struct disent *ent = disinsntable;
176384865Sobrien  struct disent *prev = ent;
176484865Sobrien
176584865Sobrien  ent->ournum = 32768;
176684865Sobrien  while ((ent = ent->next_ent) != NULL)
176784865Sobrien    {
176884865Sobrien      ent->ournum = prev->ournum + prev->nextcnt + 1;
176984865Sobrien      prev = ent;
177084865Sobrien    }
177184865Sobrien}
177284865Sobrien
1773130561Sobrienstatic void
177484865Sobrieninsert_bit_table_ent (curr_ent, bit, opcode, mask,
177584865Sobrien                      opcodenum, order, completer_index)
177684865Sobrien     struct bittree *curr_ent;
177784865Sobrien     int bit;
177884865Sobrien     ia64_insn opcode;
177984865Sobrien     ia64_insn mask;
178084865Sobrien     int opcodenum;
178184865Sobrien     int order;
178284865Sobrien     int completer_index;
178384865Sobrien{
178484865Sobrien  ia64_insn m;
178584865Sobrien  int b;
178684865Sobrien  struct bittree *next;
178784865Sobrien
178884865Sobrien  if (bit == -1)
178984865Sobrien    {
179084865Sobrien      struct disent *nent = add_dis_table_ent (curr_ent->disent,
179184865Sobrien                                               opcodenum, order,
179284865Sobrien					       completer_index);
179384865Sobrien      curr_ent->disent = nent;
179484865Sobrien      return;
179584865Sobrien    }
179684865Sobrien
179784865Sobrien  m = ((ia64_insn) 1) << bit;
179884865Sobrien
179984865Sobrien  if (mask & m)
1800130561Sobrien    b = (opcode & m) ? 1 : 0;
180184865Sobrien  else
1802130561Sobrien    b = 2;
1803130561Sobrien
180484865Sobrien  next = curr_ent->bits[b];
180584865Sobrien  if (next == NULL)
180684865Sobrien    {
180784865Sobrien      next = make_bittree_entry ();
180884865Sobrien      curr_ent->bits[b] = next;
180984865Sobrien    }
181084865Sobrien  insert_bit_table_ent (next, bit - 1, opcode, mask, opcodenum, order,
181184865Sobrien			completer_index);
181284865Sobrien}
181384865Sobrien
1814130561Sobrienstatic void
181584865Sobrienadd_dis_entry (first, opcode, mask, opcodenum, ent, completer_index)
181684865Sobrien     struct bittree *first;
181784865Sobrien     ia64_insn opcode;
181884865Sobrien     ia64_insn mask;
181984865Sobrien     int opcodenum;
182084865Sobrien     struct completer_entry *ent;
182184865Sobrien     int completer_index;
182284865Sobrien{
182384865Sobrien  if (completer_index & (1 << 20))
1824130561Sobrien    abort ();
182584865Sobrien
182684865Sobrien  while (ent != NULL)
182784865Sobrien    {
182884865Sobrien      ia64_insn newopcode = (opcode & (~ ent->mask)) | ent->bits;
182984865Sobrien      add_dis_entry (first, newopcode, mask, opcodenum, ent->addl_entries,
183084865Sobrien		     (completer_index << 1) | 1);
1831130561Sobrien
183284865Sobrien      if (ent->is_terminal)
183384865Sobrien	{
183484865Sobrien	  insert_bit_table_ent (bittree, 40, newopcode, mask,
183584865Sobrien                                opcodenum, opcode_count - ent->order - 1,
183684865Sobrien				(completer_index << 1) | 1);
183784865Sobrien	}
183884865Sobrien      completer_index <<= 1;
183984865Sobrien      ent = ent->alternative;
184084865Sobrien    }
184184865Sobrien}
184284865Sobrien
1843130561Sobrien/* This optimization pass combines multiple "don't care" nodes.  */
1844130561Sobrienstatic void
184584865Sobriencompact_distree (ent)
184684865Sobrien     struct bittree *ent;
184784865Sobrien{
184884865Sobrien#define IS_SKIP(ent) \
184984865Sobrien    ((ent->bits[2] !=NULL) \
185084865Sobrien     && (ent->bits[0] == NULL && ent->bits[1] == NULL && ent->skip_flag == 0))
185184865Sobrien
185284865Sobrien  int bitcnt = 0;
185384865Sobrien  struct bittree *nent = ent;
185484865Sobrien  int x;
185584865Sobrien
185684865Sobrien  while (IS_SKIP (nent))
185784865Sobrien    {
185884865Sobrien      bitcnt++;
185984865Sobrien      nent = nent->bits[2];
186084865Sobrien    }
186184865Sobrien
186284865Sobrien  if (bitcnt)
186384865Sobrien    {
186484865Sobrien      struct bittree *next = ent->bits[2];
186584865Sobrien
186684865Sobrien      ent->bits[0] = nent->bits[0];
186784865Sobrien      ent->bits[1] = nent->bits[1];
186884865Sobrien      ent->bits[2] = nent->bits[2];
186984865Sobrien      ent->disent = nent->disent;
187084865Sobrien      ent->skip_flag = 1;
187184865Sobrien      ent->bits_to_skip = bitcnt;
187284865Sobrien      while (next != nent)
187384865Sobrien	{
187484865Sobrien	  struct bittree *b = next;
187584865Sobrien	  next = next->bits[2];
187684865Sobrien	  free (b);
187784865Sobrien	}
187884865Sobrien      free (nent);
187984865Sobrien    }
188084865Sobrien
188184865Sobrien  for (x = 0; x < 3; x++)
188284865Sobrien    {
188384865Sobrien      struct bittree *i = ent->bits[x];
1884130561Sobrien
188584865Sobrien      if (i != NULL)
1886130561Sobrien	compact_distree (i);
188784865Sobrien    }
188884865Sobrien}
188984865Sobrien
189084865Sobrienstatic unsigned char *insn_list;
189184865Sobrienstatic int insn_list_len = 0;
189284865Sobrienstatic int tot_insn_list_len = 0;
189384865Sobrien
189484865Sobrien/* Generate the disassembler state machine corresponding to the tree
189584865Sobrien   in ENT.  */
1896130561Sobrienstatic void
189784865Sobriengen_dis_table (ent)
189884865Sobrien     struct bittree *ent;
189984865Sobrien{
190084865Sobrien  int x;
190184865Sobrien  int our_offset = insn_list_len;
190284865Sobrien  int bitsused = 5;
190384865Sobrien  int totbits = bitsused;
190484865Sobrien  int needed_bytes;
190584865Sobrien  int zero_count = 0;
1906130561Sobrien  int zero_dest = 0;	/* Initialize this with 0 to keep gcc quiet...  */
190784865Sobrien
190884865Sobrien  /* If this is a terminal entry, there's no point in skipping any
1909130561Sobrien     bits.  */
191084865Sobrien  if (ent->skip_flag && ent->bits[0] == NULL && ent->bits[1] == NULL &&
191184865Sobrien      ent->bits[2] == NULL)
191284865Sobrien    {
191384865Sobrien      if (ent->disent == NULL)
1914130561Sobrien	abort ();
191584865Sobrien      else
1916130561Sobrien	ent->skip_flag = 0;
191784865Sobrien    }
191884865Sobrien
191984865Sobrien  /* Calculate the amount of space needed for this entry, or at least
1920130561Sobrien     a conservatively large approximation.  */
192184865Sobrien  if (ent->skip_flag)
1922130561Sobrien    totbits += 5;
1923130561Sobrien
192484865Sobrien  for (x = 1; x < 3; x++)
1925130561Sobrien    if (ent->bits[x] != NULL)
1926130561Sobrien      totbits += 16;
192784865Sobrien
192884865Sobrien  if (ent->disent != NULL)
192984865Sobrien    {
193084865Sobrien      if (ent->bits[2] != NULL)
1931130561Sobrien	abort ();
1932130561Sobrien
193384865Sobrien      totbits += 16;
193484865Sobrien    }
193584865Sobrien
1936130561Sobrien  /* Now allocate the space.  */
193784865Sobrien  needed_bytes = (totbits + 7) / 8;
193884865Sobrien  if ((needed_bytes + insn_list_len) > tot_insn_list_len)
193984865Sobrien    {
194084865Sobrien      tot_insn_list_len += 256;
1941218822Sdim      insn_list = (unsigned char *) xrealloc (insn_list, tot_insn_list_len);
194284865Sobrien    }
194384865Sobrien  our_offset = insn_list_len;
194484865Sobrien  insn_list_len += needed_bytes;
194584865Sobrien  memset (insn_list + our_offset, 0, needed_bytes);
194684865Sobrien
194784865Sobrien  /* Encode the skip entry by setting bit 6 set in the state op field,
1948130561Sobrien     and store the # of bits to skip immediately after.  */
194984865Sobrien  if (ent->skip_flag)
195084865Sobrien    {
195184865Sobrien      bitsused += 5;
195284865Sobrien      insn_list[our_offset + 0] |= 0x40 | ((ent->bits_to_skip >> 2) & 0xf);
195384865Sobrien      insn_list[our_offset + 1] |= ((ent->bits_to_skip & 3) << 6);
195484865Sobrien    }
195584865Sobrien
195684865Sobrien#define IS_ONLY_IFZERO(ENT) \
195784865Sobrien  ((ENT)->bits[0] != NULL && (ENT)->bits[1] == NULL && (ENT)->bits[2] == NULL \
195884865Sobrien   && (ENT)->disent == NULL && (ENT)->skip_flag == 0)
195984865Sobrien
196084865Sobrien  /* Store an "if (bit is zero)" instruction by setting bit 7 in the
1961130561Sobrien     state op field.  */
196284865Sobrien  if (ent->bits[0] != NULL)
196384865Sobrien    {
196484865Sobrien      struct bittree *nent = ent->bits[0];
196584865Sobrien      zero_count = 0;
196684865Sobrien
196784865Sobrien      insn_list[our_offset] |= 0x80;
196884865Sobrien
196984865Sobrien      /* We can encode sequences of multiple "if (bit is zero)" tests
197084865Sobrien	 by storing the # of zero bits to check in the lower 3 bits of
197184865Sobrien	 the instruction.  However, this only applies if the state
197284865Sobrien	 solely tests for a zero bit.  */
197384865Sobrien
197484865Sobrien      if (IS_ONLY_IFZERO (ent))
197584865Sobrien	{
197684865Sobrien	  while (IS_ONLY_IFZERO (nent) && zero_count < 7)
197784865Sobrien	    {
197884865Sobrien	      nent = nent->bits[0];
197984865Sobrien	      zero_count++;
198084865Sobrien	    }
198184865Sobrien
198284865Sobrien	  insn_list[our_offset + 0] |= zero_count;
198384865Sobrien	}
198484865Sobrien      zero_dest = insn_list_len;
198584865Sobrien      gen_dis_table (nent);
198684865Sobrien    }
198784865Sobrien
198884865Sobrien  /* Now store the remaining tests.  We also handle a sole "termination
198984865Sobrien     entry" by storing it as an "any bit" test.  */
199084865Sobrien
199184865Sobrien  for (x = 1; x < 3; x++)
199284865Sobrien    {
199384865Sobrien      if (ent->bits[x] != NULL || (x == 2 && ent->disent != NULL))
199484865Sobrien	{
199584865Sobrien	  struct bittree *i = ent->bits[x];
199684865Sobrien	  int idest;
199784865Sobrien	  int currbits = 15;
199884865Sobrien
199984865Sobrien	  if (i != NULL)
200084865Sobrien	    {
200184865Sobrien	      /* If the instruction being branched to only consists of
200284865Sobrien		 a termination entry, use the termination entry as the
200384865Sobrien		 place to branch to instead.  */
200484865Sobrien	      if (i->bits[0] == NULL && i->bits[1] == NULL
200584865Sobrien		  && i->bits[2] == NULL && i->disent != NULL)
200684865Sobrien		{
200784865Sobrien		  idest = i->disent->ournum;
200884865Sobrien		  i = NULL;
200984865Sobrien		}
201084865Sobrien	      else
2011130561Sobrien		idest = insn_list_len - our_offset;
201284865Sobrien	    }
201384865Sobrien	  else
2014130561Sobrien	    idest = ent->disent->ournum;
201584865Sobrien
201684865Sobrien	  /* If the destination offset for the if (bit is 1) test is less
201784865Sobrien	     than 256 bytes away, we can store it as 8-bits instead of 16;
201884865Sobrien	     the instruction has bit 5 set for the 16-bit address, and bit
201984865Sobrien	     4 for the 8-bit address.  Since we've already allocated 16
202084865Sobrien	     bits for the address we need to deallocate the space.
202184865Sobrien
202284865Sobrien	     Note that branchings within the table are relative, and
202384865Sobrien	     there are no branches that branch past our instruction yet
2024130561Sobrien	     so we do not need to adjust any other offsets.  */
202584865Sobrien	  if (x == 1)
202684865Sobrien	    {
202784865Sobrien	      if (idest <= 256)
202884865Sobrien		{
202984865Sobrien		  int start = our_offset + bitsused / 8 + 1;
203084865Sobrien
203184865Sobrien		  memmove (insn_list + start,
203284865Sobrien			   insn_list + start + 1,
203384865Sobrien			   insn_list_len - (start + 1));
203484865Sobrien		  currbits = 7;
203584865Sobrien		  totbits -= 8;
203684865Sobrien		  needed_bytes--;
203784865Sobrien		  insn_list_len--;
203884865Sobrien		  insn_list[our_offset] |= 0x10;
203984865Sobrien		  idest--;
204084865Sobrien		}
204184865Sobrien	      else
2042130561Sobrien		insn_list[our_offset] |= 0x20;
204384865Sobrien	    }
204484865Sobrien	  else
204584865Sobrien	    {
204684865Sobrien	      /* An instruction which solely consists of a termination
204784865Sobrien		 marker and whose disassembly name index is < 4096
204884865Sobrien		 can be stored in 16 bits.  The encoding is slightly
204984865Sobrien		 odd; the upper 4 bits of the instruction are 0x3, and
205084865Sobrien		 bit 3 loses its normal meaning.  */
205184865Sobrien
205284865Sobrien	      if (ent->bits[0] == NULL && ent->bits[1] == NULL
205384865Sobrien		  && ent->bits[2] == NULL && ent->skip_flag == 0
205484865Sobrien		  && ent->disent != NULL
205584865Sobrien		  && ent->disent->ournum < (32768 + 4096))
205684865Sobrien		{
205784865Sobrien		  int start = our_offset + bitsused / 8 + 1;
205884865Sobrien
205984865Sobrien		  memmove (insn_list + start,
206084865Sobrien			   insn_list + start + 1,
206184865Sobrien			   insn_list_len - (start + 1));
206284865Sobrien		  currbits = 11;
206384865Sobrien		  totbits -= 5;
206484865Sobrien		  bitsused--;
206584865Sobrien		  needed_bytes--;
206684865Sobrien		  insn_list_len--;
206784865Sobrien		  insn_list[our_offset] |= 0x30;
206884865Sobrien		  idest &= ~32768;
206984865Sobrien		}
207084865Sobrien	      else
2071130561Sobrien		insn_list[our_offset] |= 0x08;
207284865Sobrien	    }
2073130561Sobrien
207484865Sobrien	  if (debug)
207584865Sobrien	    {
207684865Sobrien	      int id = idest;
207784865Sobrien
207884865Sobrien	      if (i == NULL)
2079130561Sobrien		id |= 32768;
208084865Sobrien	      else if (! (id & 32768))
2081130561Sobrien		id += our_offset;
2082130561Sobrien
208384865Sobrien	      if (x == 1)
2084130561Sobrien		printf ("%d: if (1) goto %d\n", our_offset, id);
208584865Sobrien	      else
2086130561Sobrien		printf ("%d: try %d\n", our_offset, id);
208784865Sobrien	    }
208884865Sobrien
2089130561Sobrien	  /* Store the address of the entry being branched to.  */
209084865Sobrien	  while (currbits >= 0)
209184865Sobrien	    {
2092218822Sdim	      unsigned char *byte = insn_list + our_offset + bitsused / 8;
209384865Sobrien
209484865Sobrien	      if (idest & (1 << currbits))
2095130561Sobrien		*byte |= (1 << (7 - (bitsused % 8)));
2096130561Sobrien
209784865Sobrien	      bitsused++;
209884865Sobrien	      currbits--;
209984865Sobrien	    }
210084865Sobrien
2101130561Sobrien	  /* Now generate the states for the entry being branched to.  */
210284865Sobrien	  if (i != NULL)
2103130561Sobrien	    gen_dis_table (i);
210484865Sobrien	}
210584865Sobrien    }
2106130561Sobrien
210784865Sobrien  if (debug)
210884865Sobrien    {
210984865Sobrien      if (ent->skip_flag)
2110130561Sobrien	printf ("%d: skipping %d\n", our_offset, ent->bits_to_skip);
211184865Sobrien
211284865Sobrien      if (ent->bits[0] != NULL)
2113130561Sobrien	printf ("%d: if (0:%d) goto %d\n", our_offset, zero_count + 1,
2114130561Sobrien		zero_dest);
211584865Sobrien    }
2116130561Sobrien
211784865Sobrien  if (bitsused != totbits)
2118130561Sobrien    abort ();
211984865Sobrien}
212084865Sobrien
2121130561Sobrienstatic void
2122130561Sobrienprint_dis_table (void)
212384865Sobrien{
212484865Sobrien  int x;
212584865Sobrien  struct disent *cent = disinsntable;
212684865Sobrien
212784865Sobrien  printf ("static const char dis_table[] = {\n");
212884865Sobrien  for (x = 0; x < insn_list_len; x++)
212984865Sobrien    {
213084865Sobrien      if ((x > 0) && ((x % 12) == 0))
2131130561Sobrien	printf ("\n");
2132130561Sobrien
213384865Sobrien      printf ("0x%02x, ", insn_list[x]);
213484865Sobrien    }
213584865Sobrien  printf ("\n};\n\n");
213684865Sobrien
213784865Sobrien  printf ("static const struct ia64_dis_names ia64_dis_names[] = {\n");
213884865Sobrien  while (cent != NULL)
213984865Sobrien    {
214084865Sobrien      struct disent *ent = cent;
214184865Sobrien
214284865Sobrien      while (ent != NULL)
214384865Sobrien	{
214484865Sobrien	  printf ("{ 0x%x, %d, %d, %d },\n", ent->completer_index,
214584865Sobrien		  ent->insn, (ent->nexte != NULL ? 1 : 0),
214684865Sobrien                  ent->priority);
214784865Sobrien	  ent = ent->nexte;
214884865Sobrien	}
214984865Sobrien      cent = cent->next_ent;
215084865Sobrien    }
215184865Sobrien  printf ("};\n\n");
215284865Sobrien}
215384865Sobrien
2154130561Sobrienstatic void
2155130561Sobriengenerate_disassembler (void)
215684865Sobrien{
215784865Sobrien  int i;
215884865Sobrien
215984865Sobrien  bittree = make_bittree_entry ();
216084865Sobrien
2161130561Sobrien  for (i = 0; i < otlen; i++)
216284865Sobrien    {
216384865Sobrien      struct main_entry *ptr = ordered_table[i];
216484865Sobrien
216584865Sobrien      if (ptr->opcode->type != IA64_TYPE_DYN)
2166130561Sobrien	add_dis_entry (bittree,
2167130561Sobrien		       ptr->opcode->opcode, ptr->opcode->mask,
2168130561Sobrien		       ptr->main_index,
2169130561Sobrien		       ptr->completers, 1);
217084865Sobrien    }
217184865Sobrien
217284865Sobrien  compact_distree (bittree);
217384865Sobrien  finish_distable ();
217484865Sobrien  gen_dis_table (bittree);
217584865Sobrien
217684865Sobrien  print_dis_table ();
217784865Sobrien}
217884865Sobrien
2179130561Sobrienstatic void
2180130561Sobrienprint_string_table (void)
218184865Sobrien{
218284865Sobrien  int x;
218384865Sobrien  char lbuf[80], buf[80];
218484865Sobrien  int blen = 0;
218584865Sobrien
2186130561Sobrien  printf ("static const char * const ia64_strings[] = {\n");
218784865Sobrien  lbuf[0] = '\0';
2188130561Sobrien
218984865Sobrien  for (x = 0; x < strtablen; x++)
219084865Sobrien    {
219184865Sobrien      int len;
219284865Sobrien
219384865Sobrien      if (strlen (string_table[x]->s) > 75)
2194130561Sobrien	abort ();
2195130561Sobrien
219684865Sobrien      sprintf (buf, " \"%s\",", string_table[x]->s);
219784865Sobrien      len = strlen (buf);
2198130561Sobrien
219984865Sobrien      if ((blen + len) > 75)
220084865Sobrien	{
220184865Sobrien	  printf (" %s\n", lbuf);
220284865Sobrien	  lbuf[0] = '\0';
220384865Sobrien	  blen = 0;
220484865Sobrien	}
220584865Sobrien      strcat (lbuf, buf);
220684865Sobrien      blen += len;
220784865Sobrien    }
2208130561Sobrien
220984865Sobrien  if (blen > 0)
2210130561Sobrien    printf (" %s\n", lbuf);
2211130561Sobrien
221284865Sobrien  printf ("};\n\n");
221384865Sobrien}
221484865Sobrien
221584865Sobrienstatic struct completer_entry **glist;
221684865Sobrienstatic int glistlen = 0;
221784865Sobrienstatic int glisttotlen = 0;
221884865Sobrien
2219130561Sobrien/* If the completer trees ENT1 and ENT2 are equal, return 1.  */
222084865Sobrien
2221130561Sobrienstatic int
222284865Sobriencompleter_entries_eq (ent1, ent2)
222384865Sobrien     struct completer_entry *ent1, *ent2;
222484865Sobrien{
222584865Sobrien  while (ent1 != NULL && ent2 != NULL)
222684865Sobrien    {
222784865Sobrien      if (ent1->name->num != ent2->name->num
222884865Sobrien	  || ent1->bits != ent2->bits
222984865Sobrien	  || ent1->mask != ent2->mask
223084865Sobrien	  || ent1->is_terminal != ent2->is_terminal
223184865Sobrien          || ent1->dependencies != ent2->dependencies
223284865Sobrien          || ent1->order != ent2->order)
2233130561Sobrien	return 0;
2234130561Sobrien
223584865Sobrien      if (! completer_entries_eq (ent1->addl_entries, ent2->addl_entries))
2236130561Sobrien	return 0;
2237130561Sobrien
223884865Sobrien      ent1 = ent1->alternative;
223984865Sobrien      ent2 = ent2->alternative;
224084865Sobrien    }
2241130561Sobrien
224284865Sobrien  return ent1 == ent2;
224384865Sobrien}
224484865Sobrien
224584865Sobrien/* Insert ENT into the global list of completers and return it.  If an
224684865Sobrien   equivalent entry (according to completer_entries_eq) already exists,
2247130561Sobrien   it is returned instead.  */
2248130561Sobrienstatic struct completer_entry *
2249130561Sobrieninsert_gclist (struct completer_entry *ent)
225084865Sobrien{
225184865Sobrien  if (ent != NULL)
225284865Sobrien    {
225384865Sobrien      int i;
225484865Sobrien      int x;
225584865Sobrien      int start = 0, end;
225684865Sobrien
225784865Sobrien      ent->addl_entries = insert_gclist (ent->addl_entries);
225884865Sobrien      ent->alternative = insert_gclist (ent->alternative);
225984865Sobrien
226084865Sobrien      i = glistlen / 2;
226184865Sobrien      end = glistlen;
226284865Sobrien
226384865Sobrien      if (glisttotlen == glistlen)
226484865Sobrien	{
226584865Sobrien	  glisttotlen += 20;
226684865Sobrien	  glist = (struct completer_entry **)
226784865Sobrien	    xrealloc (glist, sizeof (struct completer_entry *) * glisttotlen);
226884865Sobrien	}
226984865Sobrien
227084865Sobrien      if (glistlen == 0)
227184865Sobrien	{
227284865Sobrien	  glist[0] = ent;
227384865Sobrien	  glistlen = 1;
227484865Sobrien	  return ent;
227584865Sobrien	}
227684865Sobrien
227784865Sobrien      if (ent->name->num < glist[0]->name->num)
2278130561Sobrien	i = 0;
227984865Sobrien      else if (ent->name->num > glist[end - 1]->name->num)
2280130561Sobrien	i = end;
228184865Sobrien      else
228284865Sobrien	{
228384865Sobrien	  int c;
228484865Sobrien
228584865Sobrien	  while (1)
228684865Sobrien	    {
228784865Sobrien	      i = (start + end) / 2;
228884865Sobrien	      c = ent->name->num - glist[i]->name->num;
2289130561Sobrien
229084865Sobrien	      if (c < 0)
2291130561Sobrien		end = i - 1;
229284865Sobrien	      else if (c == 0)
229384865Sobrien		{
229484865Sobrien		  while (i > 0
229584865Sobrien			 && ent->name->num == glist[i - 1]->name->num)
2296130561Sobrien		    i--;
2297130561Sobrien
229884865Sobrien		  break;
229984865Sobrien		}
230084865Sobrien	      else
2301130561Sobrien		start = i + 1;
2302130561Sobrien
230384865Sobrien	      if (start > end)
2304130561Sobrien		break;
230584865Sobrien	    }
2306130561Sobrien
230784865Sobrien	  if (c == 0)
230884865Sobrien	    {
230984865Sobrien	      while (i < glistlen)
231084865Sobrien		{
231184865Sobrien		  if (ent->name->num != glist[i]->name->num)
2312130561Sobrien		    break;
2313130561Sobrien
231484865Sobrien		  if (completer_entries_eq (ent, glist[i]))
2315130561Sobrien		    return glist[i];
2316130561Sobrien
231784865Sobrien		  i++;
231884865Sobrien		}
231984865Sobrien	    }
232084865Sobrien	}
2321130561Sobrien
232284865Sobrien      for (; i > 0 && i < glistlen; i--)
2323130561Sobrien	if (ent->name->num >= glist[i - 1]->name->num)
2324130561Sobrien	  break;
2325130561Sobrien
232684865Sobrien      for (; i < glistlen; i++)
2327130561Sobrien	if (ent->name->num < glist[i]->name->num)
2328130561Sobrien	  break;
2329130561Sobrien
233084865Sobrien      for (x = glistlen - 1; x >= i; x--)
2331130561Sobrien	glist[x + 1] = glist[x];
2332130561Sobrien
233384865Sobrien      glist[i] = ent;
233484865Sobrien      glistlen++;
233584865Sobrien    }
233684865Sobrien  return ent;
233784865Sobrien}
233884865Sobrien
233984865Sobrienstatic int
234084865Sobrienget_prefix_len (name)
234184865Sobrien     const char *name;
234284865Sobrien{
234384865Sobrien  char *c;
234484865Sobrien
234584865Sobrien  if (name[0] == '\0')
2346130561Sobrien    return 0;
234784865Sobrien
234884865Sobrien  c = strchr (name, '.');
234984865Sobrien  if (c != NULL)
2350130561Sobrien    return c - name;
235184865Sobrien  else
2352130561Sobrien    return strlen (name);
235384865Sobrien}
235484865Sobrien
235584865Sobrienstatic void
235684865Sobriencompute_completer_bits (ment, ent)
235784865Sobrien     struct main_entry *ment;
235884865Sobrien     struct completer_entry *ent;
235984865Sobrien{
236084865Sobrien  while (ent != NULL)
236184865Sobrien    {
236284865Sobrien      compute_completer_bits (ment, ent->addl_entries);
236384865Sobrien
236484865Sobrien      if (ent->is_terminal)
236584865Sobrien	{
236684865Sobrien	  ia64_insn mask = 0;
236784865Sobrien	  ia64_insn our_bits = ent->bits;
236884865Sobrien	  struct completer_entry *p = ent->parent;
236984865Sobrien	  ia64_insn p_bits;
237084865Sobrien	  int x;
237184865Sobrien
237284865Sobrien	  while (p != NULL && ! p->is_terminal)
2373130561Sobrien	    p = p->parent;
237484865Sobrien
237584865Sobrien	  if (p != NULL)
2376130561Sobrien	    p_bits = p->bits;
237784865Sobrien	  else
2378130561Sobrien	    p_bits = ment->opcode->opcode;
237984865Sobrien
238084865Sobrien	  for (x = 0; x < 64; x++)
238184865Sobrien	    {
238284865Sobrien	      ia64_insn m = ((ia64_insn) 1) << x;
2383130561Sobrien
238484865Sobrien	      if ((p_bits & m) != (our_bits & m))
2385130561Sobrien		mask |= m;
238684865Sobrien	      else
2387130561Sobrien		our_bits &= ~m;
238884865Sobrien	    }
238984865Sobrien	  ent->bits = our_bits;
239084865Sobrien	  ent->mask = mask;
239184865Sobrien	}
239284865Sobrien      else
239384865Sobrien	{
239484865Sobrien	  ent->bits = 0;
239584865Sobrien	  ent->mask = 0;
239684865Sobrien	}
239784865Sobrien
239884865Sobrien      ent = ent->alternative;
239984865Sobrien    }
240084865Sobrien}
240184865Sobrien
240284865Sobrien/* Find identical completer trees that are used in different
2403130561Sobrien   instructions and collapse their entries.  */
2404130561Sobrienstatic void
2405130561Sobriencollapse_redundant_completers (void)
240684865Sobrien{
240784865Sobrien  struct main_entry *ptr;
240884865Sobrien  int x;
240984865Sobrien
241084865Sobrien  for (ptr = maintable; ptr != NULL; ptr = ptr->next)
241184865Sobrien    {
241284865Sobrien      if (ptr->completers == NULL)
2413130561Sobrien	abort ();
2414130561Sobrien
241584865Sobrien      compute_completer_bits (ptr, ptr->completers);
241684865Sobrien      ptr->completers = insert_gclist (ptr->completers);
241784865Sobrien    }
241884865Sobrien
241984865Sobrien  /* The table has been finalized, now number the indexes.  */
242084865Sobrien  for (x = 0; x < glistlen; x++)
2421130561Sobrien    glist[x]->num = x;
242284865Sobrien}
242384865Sobrien
242484865Sobrien
2425130561Sobrien/* Attach two lists of dependencies to each opcode.
242684865Sobrien   1) all resources which, when already marked in use, conflict with this
242784865Sobrien   opcode (chks)
242884865Sobrien   2) all resources which must be marked in use when this opcode is used
2429130561Sobrien   (regs).  */
2430130561Sobrienstatic int
243184865Sobrieninsert_opcode_dependencies (opc, cmp)
243284865Sobrien     struct ia64_opcode *opc;
243384865Sobrien     struct completer_entry *cmp ATTRIBUTE_UNUSED;
243484865Sobrien{
2435130561Sobrien  /* Note all resources which point to this opcode.  rfi has the most chks
2436130561Sobrien     (79) and cmpxchng has the most regs (54) so 100 here should be enough.  */
243784865Sobrien  int i;
243884865Sobrien  int nregs = 0;
243984865Sobrien  unsigned short regs[256];
244084865Sobrien  int nchks = 0;
244184865Sobrien  unsigned short chks[256];
2442130561Sobrien  /* Flag insns for which no class matched; there should be none.  */
244384865Sobrien  int no_class_found = 1;
244484865Sobrien
2445130561Sobrien  for (i = 0; i < rdepslen; i++)
244684865Sobrien    {
244784865Sobrien      struct rdep *rs = rdeps[i];
244884865Sobrien      int j;
244984865Sobrien
245084865Sobrien      if (strcmp (opc->name, "cmp.eq.and") == 0
2451218822Sdim          && CONST_STRNEQ (rs->name, "PR%")
245284865Sobrien          && rs->mode == 1)
245384865Sobrien        no_class_found = 99;
245484865Sobrien
245584865Sobrien      for (j=0; j < rs->nregs;j++)
245684865Sobrien        {
245784865Sobrien          int ic_note = 0;
245884865Sobrien
245984865Sobrien          if (in_iclass (opc, ics[rs->regs[j]], NULL, NULL, &ic_note))
246084865Sobrien            {
2461130561Sobrien              /* We can ignore ic_note 11 for non PR resources.  */
2462218822Sdim              if (ic_note == 11 && ! CONST_STRNEQ (rs->name, "PR"))
246384865Sobrien                ic_note = 0;
246484865Sobrien
246584865Sobrien              if (ic_note != 0 && rs->regnotes[j] != 0
246684865Sobrien                  && ic_note != rs->regnotes[j]
246784865Sobrien                  && !(ic_note == 11 && rs->regnotes[j] == 1))
2468130561Sobrien                warn (_("IC note %d in opcode %s (IC:%s) conflicts with resource %s note %d\n"),
2469130561Sobrien		      ic_note, opc->name, ics[rs->regs[j]]->name,
2470130561Sobrien		      rs->name, rs->regnotes[j]);
247184865Sobrien              /* Instruction class notes override resource notes.
247284865Sobrien                 So far, only note 11 applies to an IC instead of a resource,
2473130561Sobrien                 and note 11 implies note 1.  */
247484865Sobrien              if (ic_note)
247584865Sobrien                regs[nregs++] = RDEP(ic_note, i);
247684865Sobrien              else
247784865Sobrien                regs[nregs++] = RDEP(rs->regnotes[j], i);
247884865Sobrien              no_class_found = 0;
247984865Sobrien              ++rs->total_regs;
248084865Sobrien            }
248184865Sobrien        }
2482130561Sobrien
2483130561Sobrien      for (j = 0; j < rs->nchks; j++)
248484865Sobrien        {
248584865Sobrien          int ic_note = 0;
248684865Sobrien
248784865Sobrien          if (in_iclass (opc, ics[rs->chks[j]], NULL, NULL, &ic_note))
248884865Sobrien            {
2489130561Sobrien              /* We can ignore ic_note 11 for non PR resources.  */
2490218822Sdim              if (ic_note == 11 && ! CONST_STRNEQ (rs->name, "PR"))
249184865Sobrien                ic_note = 0;
249284865Sobrien
249384865Sobrien              if (ic_note != 0 && rs->chknotes[j] != 0
249484865Sobrien                  && ic_note != rs->chknotes[j]
249584865Sobrien                  && !(ic_note == 11 && rs->chknotes[j] == 1))
2496130561Sobrien                warn (_("IC note %d for opcode %s (IC:%s) conflicts with resource %s note %d\n"),
2497130561Sobrien		      ic_note, opc->name, ics[rs->chks[j]]->name,
2498130561Sobrien		      rs->name, rs->chknotes[j]);
249984865Sobrien              if (ic_note)
250084865Sobrien                chks[nchks++] = RDEP(ic_note, i);
250184865Sobrien              else
250284865Sobrien                chks[nchks++] = RDEP(rs->chknotes[j], i);
250384865Sobrien              no_class_found = 0;
250484865Sobrien              ++rs->total_chks;
250584865Sobrien            }
250684865Sobrien        }
250784865Sobrien    }
250884865Sobrien
250984865Sobrien  if (no_class_found)
2510130561Sobrien    warn (_("opcode %s has no class (ops %d %d %d)\n"),
2511130561Sobrien	  opc->name,
2512130561Sobrien	  opc->operands[0], opc->operands[1], opc->operands[2]);
251384865Sobrien
251484865Sobrien  return insert_dependencies (nchks, chks, nregs, regs);
251584865Sobrien}
251684865Sobrien
2517130561Sobrienstatic void
251884865Sobrieninsert_completer_entry (opc, tabent, order)
251984865Sobrien     struct ia64_opcode *opc;
252084865Sobrien     struct main_entry *tabent;
252184865Sobrien     int order;
252284865Sobrien{
252384865Sobrien  struct completer_entry **ptr = &tabent->completers;
252484865Sobrien  struct completer_entry *parent = NULL;
252584865Sobrien  char pcopy[129], *prefix;
252684865Sobrien  int at_end = 0;
252784865Sobrien
252884865Sobrien  if (strlen (opc->name) > 128)
2529130561Sobrien    abort ();
2530130561Sobrien
253184865Sobrien  strcpy (pcopy, opc->name);
253284865Sobrien  prefix = pcopy + get_prefix_len (pcopy);
2533130561Sobrien
253484865Sobrien  if (prefix[0] != '\0')
2535130561Sobrien    prefix++;
253684865Sobrien
253784865Sobrien  while (! at_end)
253884865Sobrien    {
253984865Sobrien      int need_new_ent = 1;
254084865Sobrien      int plen = get_prefix_len (prefix);
254184865Sobrien      struct string_entry *sent;
254284865Sobrien
254384865Sobrien      at_end = (prefix[plen] == '\0');
254484865Sobrien      prefix[plen] = '\0';
254584865Sobrien      sent = insert_string (prefix);
254684865Sobrien
254784865Sobrien      while (*ptr != NULL)
254884865Sobrien	{
254984865Sobrien	  int cmpres = sent->num - (*ptr)->name->num;
255084865Sobrien
255184865Sobrien	  if (cmpres == 0)
255284865Sobrien	    {
255384865Sobrien	      need_new_ent = 0;
255484865Sobrien	      break;
255584865Sobrien	    }
255684865Sobrien	  else
2557130561Sobrien	    ptr = &((*ptr)->alternative);
255884865Sobrien	}
2559130561Sobrien
256084865Sobrien      if (need_new_ent)
256184865Sobrien	{
256284865Sobrien	  struct completer_entry *nent = tmalloc (struct completer_entry);
2563130561Sobrien
256484865Sobrien	  nent->name = sent;
256584865Sobrien	  nent->parent = parent;
256684865Sobrien	  nent->addl_entries = NULL;
256784865Sobrien	  nent->alternative = *ptr;
256884865Sobrien	  *ptr = nent;
256984865Sobrien	  nent->is_terminal = 0;
257084865Sobrien          nent->dependencies = -1;
257184865Sobrien	}
257284865Sobrien
257384865Sobrien      if (! at_end)
257484865Sobrien	{
257584865Sobrien	  parent = *ptr;
257684865Sobrien	  ptr = &((*ptr)->addl_entries);
257784865Sobrien	  prefix += plen + 1;
257884865Sobrien	}
257984865Sobrien    }
258084865Sobrien
258184865Sobrien  if ((*ptr)->is_terminal)
2582130561Sobrien    abort ();
258384865Sobrien
258484865Sobrien  (*ptr)->is_terminal = 1;
258584865Sobrien  (*ptr)->mask = (ia64_insn)-1;
258684865Sobrien  (*ptr)->bits = opc->opcode;
258784865Sobrien  (*ptr)->dependencies = insert_opcode_dependencies (opc, *ptr);
258884865Sobrien  (*ptr)->order = order;
258984865Sobrien}
259084865Sobrien
2591130561Sobrienstatic void
259284865Sobrienprint_completer_entry (ent)
259384865Sobrien     struct completer_entry *ent;
259484865Sobrien{
259584865Sobrien  int moffset = 0;
259684865Sobrien  ia64_insn mask = ent->mask, bits = ent->bits;
259784865Sobrien
259884865Sobrien  if (mask != 0)
259984865Sobrien    {
260084865Sobrien      while (! (mask & 1))
260184865Sobrien	{
260284865Sobrien	  moffset++;
260384865Sobrien	  mask = mask >> 1;
260484865Sobrien	  bits = bits >> 1;
260584865Sobrien	}
2606130561Sobrien
260784865Sobrien      if (bits & 0xffffffff00000000LL)
2608130561Sobrien	abort ();
260984865Sobrien    }
261084865Sobrien
261184865Sobrien  printf ("  { 0x%x, 0x%x, %d, %d, %d, %d, %d, %d },\n",
261284865Sobrien	  (int)bits,
261384865Sobrien	  (int)mask,
261484865Sobrien	  ent->name->num,
261584865Sobrien	  ent->alternative != NULL ? ent->alternative->num : -1,
261684865Sobrien	  ent->addl_entries != NULL ? ent->addl_entries->num : -1,
261784865Sobrien	  moffset,
261884865Sobrien	  ent->is_terminal ? 1 : 0,
261984865Sobrien          ent->dependencies);
262084865Sobrien}
262184865Sobrien
2622130561Sobrienstatic void
262384865Sobrienprint_completer_table ()
262484865Sobrien{
262584865Sobrien  int x;
262684865Sobrien
262784865Sobrien  printf ("static const struct ia64_completer_table\ncompleter_table[] = {\n");
262884865Sobrien  for (x = 0; x < glistlen; x++)
2629130561Sobrien    print_completer_entry (glist[x]);
263084865Sobrien  printf ("};\n\n");
263184865Sobrien}
263284865Sobrien
2633130561Sobrienstatic int
263484865Sobrienopcodes_eq (opc1, opc2)
263584865Sobrien     struct ia64_opcode *opc1;
263684865Sobrien     struct ia64_opcode *opc2;
263784865Sobrien{
263884865Sobrien  int x;
263984865Sobrien  int plen1, plen2;
264084865Sobrien
264184865Sobrien  if ((opc1->mask != opc2->mask) || (opc1->type != opc2->type)
264284865Sobrien      || (opc1->num_outputs != opc2->num_outputs)
264384865Sobrien      || (opc1->flags != opc2->flags))
2644130561Sobrien    return 0;
2645130561Sobrien
2646130561Sobrien  for (x = 0; x < 5; x++)
2647130561Sobrien    if (opc1->operands[x] != opc2->operands[x])
264884865Sobrien      return 0;
2649130561Sobrien
265084865Sobrien  plen1 = get_prefix_len (opc1->name);
265184865Sobrien  plen2 = get_prefix_len (opc2->name);
2652130561Sobrien
265384865Sobrien  if (plen1 == plen2 && (memcmp (opc1->name, opc2->name, plen1) == 0))
2654130561Sobrien    return 1;
2655130561Sobrien
265684865Sobrien  return 0;
265784865Sobrien}
265884865Sobrien
2659130561Sobrienstatic void
266084865Sobrienadd_opcode_entry (opc)
266184865Sobrien     struct ia64_opcode *opc;
266284865Sobrien{
266384865Sobrien  struct main_entry **place;
266484865Sobrien  struct string_entry *name;
266584865Sobrien  char prefix[129];
266684865Sobrien  int found_it = 0;
266784865Sobrien
266884865Sobrien  if (strlen (opc->name) > 128)
2669130561Sobrien    abort ();
2670130561Sobrien
267184865Sobrien  place = &maintable;
267284865Sobrien  strcpy (prefix, opc->name);
267384865Sobrien  prefix[get_prefix_len (prefix)] = '\0';
267484865Sobrien  name = insert_string (prefix);
267584865Sobrien
267684865Sobrien  /* Walk the list of opcode table entries.  If it's a new
267784865Sobrien     instruction, allocate and fill in a new entry.  Note
2678130561Sobrien     the main table is alphabetical by opcode name.  */
267984865Sobrien
268084865Sobrien  while (*place != NULL)
268184865Sobrien    {
268284865Sobrien      if ((*place)->name->num == name->num
268384865Sobrien	  && opcodes_eq ((*place)->opcode, opc))
268484865Sobrien	{
268584865Sobrien	  found_it = 1;
268684865Sobrien	  break;
268784865Sobrien	}
268884865Sobrien      if ((*place)->name->num > name->num)
2689130561Sobrien	break;
2690130561Sobrien
269184865Sobrien      place = &((*place)->next);
269284865Sobrien    }
269384865Sobrien  if (! found_it)
269484865Sobrien    {
269584865Sobrien      struct main_entry *nent = tmalloc (struct main_entry);
269684865Sobrien
269784865Sobrien      nent->name = name;
269884865Sobrien      nent->opcode = opc;
269984865Sobrien      nent->next = *place;
270084865Sobrien      nent->completers = 0;
270184865Sobrien      *place = nent;
270284865Sobrien
270384865Sobrien      if (otlen == ottotlen)
270484865Sobrien        {
270584865Sobrien          ottotlen += 20;
270684865Sobrien          ordered_table = (struct main_entry **)
270784865Sobrien            xrealloc (ordered_table, sizeof (struct main_entry *) * ottotlen);
270884865Sobrien        }
270984865Sobrien      ordered_table[otlen++] = nent;
271084865Sobrien    }
271184865Sobrien
271284865Sobrien  insert_completer_entry (opc, *place, opcode_count++);
271384865Sobrien}
271484865Sobrien
2715130561Sobrienstatic void
2716130561Sobrienprint_main_table (void)
271784865Sobrien{
271884865Sobrien  struct main_entry *ptr = maintable;
271984865Sobrien  int index = 0;
272084865Sobrien
272184865Sobrien  printf ("static const struct ia64_main_table\nmain_table[] = {\n");
272284865Sobrien  while (ptr != NULL)
272384865Sobrien    {
272484865Sobrien      printf ("  { %d, %d, %d, 0x",
272584865Sobrien	      ptr->name->num,
272684865Sobrien	      ptr->opcode->type,
272784865Sobrien	      ptr->opcode->num_outputs);
2728218822Sdim      opcode_fprintf_vma (stdout, ptr->opcode->opcode);
272984865Sobrien      printf ("ull, 0x");
2730218822Sdim      opcode_fprintf_vma (stdout, ptr->opcode->mask);
273184865Sobrien      printf ("ull, { %d, %d, %d, %d, %d }, 0x%x, %d, },\n",
273284865Sobrien	      ptr->opcode->operands[0],
273384865Sobrien	      ptr->opcode->operands[1],
273484865Sobrien	      ptr->opcode->operands[2],
273584865Sobrien	      ptr->opcode->operands[3],
273684865Sobrien	      ptr->opcode->operands[4],
273784865Sobrien	      ptr->opcode->flags,
273884865Sobrien	      ptr->completers->num);
273984865Sobrien
274084865Sobrien      ptr->main_index = index++;
274184865Sobrien
274284865Sobrien      ptr = ptr->next;
274384865Sobrien    }
274484865Sobrien  printf ("};\n\n");
274584865Sobrien}
274684865Sobrien
2747130561Sobrienstatic void
274884865Sobrienshrink (table)
274984865Sobrien     struct ia64_opcode *table;
275084865Sobrien{
275184865Sobrien  int curr_opcode;
275284865Sobrien
275384865Sobrien  for (curr_opcode = 0; table[curr_opcode].name != NULL; curr_opcode++)
2754218822Sdim    {
2755218822Sdim      add_opcode_entry (table + curr_opcode);
2756218822Sdim      if (table[curr_opcode].num_outputs == 2
2757218822Sdim	  && ((table[curr_opcode].operands[0] == IA64_OPND_P1
2758218822Sdim	       && table[curr_opcode].operands[1] == IA64_OPND_P2)
2759218822Sdim	      || (table[curr_opcode].operands[0] == IA64_OPND_P2
2760218822Sdim		  && table[curr_opcode].operands[1] == IA64_OPND_P1)))
2761218822Sdim	{
2762218822Sdim	  struct ia64_opcode *alias = tmalloc(struct ia64_opcode);
2763218822Sdim	  unsigned i;
2764218822Sdim
2765218822Sdim	  *alias = table[curr_opcode];
2766218822Sdim	  for (i = 2; i < NELEMS (alias->operands); ++i)
2767218822Sdim	    alias->operands[i - 1] = alias->operands[i];
2768218822Sdim	  alias->operands[NELEMS (alias->operands) - 1] = IA64_OPND_NIL;
2769218822Sdim	  --alias->num_outputs;
2770218822Sdim	  alias->flags |= PSEUDO;
2771218822Sdim	  add_opcode_entry (alias);
2772218822Sdim	}
2773218822Sdim    }
277484865Sobrien}
277584865Sobrien
2776130561Sobrien
2777130561Sobrien/* Program options.  */
2778130561Sobrien#define OPTION_SRCDIR	200
2779130561Sobrien
2780130561Sobrienstruct option long_options[] =
2781130561Sobrien{
2782130561Sobrien  {"srcdir",  required_argument, NULL, OPTION_SRCDIR},
2783130561Sobrien  {"debug",   no_argument,       NULL, 'd'},
2784130561Sobrien  {"version", no_argument,       NULL, 'V'},
2785130561Sobrien  {"help",    no_argument,       NULL, 'h'},
2786130561Sobrien  {0,         no_argument,       NULL, 0}
2787130561Sobrien};
2788130561Sobrien
2789130561Sobrienstatic void
2790130561Sobrienprint_version (void)
2791130561Sobrien{
2792130561Sobrien  printf ("%s: version 1.0\n", program_name);
2793130561Sobrien  xexit (0);
2794130561Sobrien}
2795130561Sobrien
2796130561Sobrienstatic void
2797130561Sobrienusage (FILE * stream, int status)
2798130561Sobrien{
2799130561Sobrien  fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
2800130561Sobrien	   program_name);
2801130561Sobrien  xexit (status);
2802130561Sobrien}
2803130561Sobrien
280484865Sobrienint
2805130561Sobrienmain (int argc, char **argv)
280684865Sobrien{
2807130561Sobrien  extern int chdir (char *);
2808130561Sobrien  char *srcdir = NULL;
2809130561Sobrien  int c;
2810130561Sobrien
2811130561Sobrien  program_name = *argv;
2812130561Sobrien  xmalloc_set_program_name (program_name);
281384865Sobrien
2814130561Sobrien  while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF)
2815130561Sobrien    switch (c)
2816130561Sobrien      {
2817130561Sobrien      case OPTION_SRCDIR:
2818130561Sobrien	srcdir = optarg;
2819130561Sobrien	break;
2820130561Sobrien      case 'V':
2821130561Sobrien      case 'v':
2822130561Sobrien	print_version ();
2823130561Sobrien	break;
2824130561Sobrien      case 'd':
2825130561Sobrien	debug = 1;
2826130561Sobrien	break;
2827130561Sobrien      case 'h':
2828130561Sobrien      case '?':
2829130561Sobrien	usage (stderr, 0);
2830130561Sobrien      default:
2831130561Sobrien      case 0:
2832130561Sobrien	break;
2833130561Sobrien      }
283484865Sobrien
2835130561Sobrien  if (optind != argc)
2836130561Sobrien    usage (stdout, 1);
2837130561Sobrien
2838130561Sobrien  if (srcdir != NULL)
2839130561Sobrien    if (chdir (srcdir) != 0)
2840130561Sobrien      fail (_("unable to change directory to \"%s\", errno = %s\n"),
2841130561Sobrien	    srcdir, strerror (errno));
2842130561Sobrien
2843130561Sobrien  load_insn_classes ();
2844130561Sobrien  load_dependencies ();
2845130561Sobrien
284684865Sobrien  shrink (ia64_opcodes_a);
284784865Sobrien  shrink (ia64_opcodes_b);
284884865Sobrien  shrink (ia64_opcodes_f);
284984865Sobrien  shrink (ia64_opcodes_i);
285084865Sobrien  shrink (ia64_opcodes_m);
285184865Sobrien  shrink (ia64_opcodes_x);
285284865Sobrien  shrink (ia64_opcodes_d);
285384865Sobrien
285484865Sobrien  collapse_redundant_completers ();
285584865Sobrien
2856130561Sobrien  printf ("/* This file is automatically generated by ia64-gen.  Do not edit!  */\n");
285784865Sobrien  print_string_table ();
285884865Sobrien  print_dependency_table ();
285984865Sobrien  print_completer_table ();
286084865Sobrien  print_main_table ();
286184865Sobrien
286284865Sobrien  generate_disassembler ();
286384865Sobrien
286484865Sobrien  exit (0);
286584865Sobrien}
2866