| /* ia64-gen.c -- Generate a shrunk set of opcode tables | 
 |    Copyright (C) 1999-2024 Free Software Foundation, Inc. | 
 |    Written by Bob Manson, Cygnus Solutions, <manson@cygnus.com> | 
 |  | 
 |    This file is part of the GNU opcodes library. | 
 |  | 
 |    This library is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3, or (at your option) | 
 |    any later version. | 
 |  | 
 |    It is distributed in the hope that it will be useful, but WITHOUT | 
 |    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
 |    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
 |    License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this file; see the file COPYING.  If not, write to the | 
 |    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA | 
 |    02110-1301, USA.  */ | 
 |  | 
 |  | 
 | /* While the ia64-opc-* set of opcode tables are easy to maintain, | 
 |    they waste a tremendous amount of space.  ia64-gen rearranges the | 
 |    instructions into a directed acyclic graph (DAG) of instruction opcodes and | 
 |    their possible completers, as well as compacting the set of strings used. | 
 |  | 
 |    The disassembler table consists of a state machine that does | 
 |    branching based on the bits of the opcode being disassembled.  The | 
 |    state encodings have been chosen to minimize the amount of space | 
 |    required. | 
 |  | 
 |    The resource table is constructed based on some text dependency tables, | 
 |    which are also easier to maintain than the final representation.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include <stdio.h> | 
 | #include <stdarg.h> | 
 | #include <errno.h> | 
 |  | 
 | #include "libiberty.h" | 
 | #include "safe-ctype.h" | 
 | #include "getopt.h" | 
 | #include "ia64-opc.h" | 
 | #include "ia64-opc-a.c" | 
 | #include "ia64-opc-i.c" | 
 | #include "ia64-opc-m.c" | 
 | #include "ia64-opc-b.c" | 
 | #include "ia64-opc-f.c" | 
 | #include "ia64-opc-x.c" | 
 | #include "ia64-opc-d.c" | 
 |  | 
 | #include <libintl.h> | 
 | #define _(String) gettext (String) | 
 |  | 
 | const char * program_name = NULL; | 
 | int debug = 0; | 
 |  | 
 | #define NELEMS(a) (sizeof (a) / sizeof ((a)[0])) | 
 | #define tmalloc(X) (X *) xmalloc (sizeof (X)) | 
 |  | 
 | typedef unsigned long long  ci_t; | 
 | /* The main opcode table entry.  Each entry is a unique combination of | 
 |    name and flags (no two entries in the table compare as being equal | 
 |    via opcodes_eq).  */ | 
 | struct main_entry | 
 | { | 
 |   /* The base name of this opcode.  The names of its completers are | 
 |      appended to it to generate the full instruction name.  */ | 
 |   struct string_entry *name; | 
 |   /* The base opcode entry.  Which one to use is a fairly arbitrary choice; | 
 |      it uses the first one passed to add_opcode_entry.  */ | 
 |   struct ia64_opcode *opcode; | 
 |   /* The list of completers that can be applied to this opcode.  */ | 
 |   struct completer_entry *completers; | 
 |   /* Next entry in the chain.  */ | 
 |   struct main_entry *next; | 
 |   /* Index in the  main table.  */ | 
 |   int main_index; | 
 | } *maintable, **ordered_table; | 
 |  | 
 | int otlen = 0; | 
 | int ottotlen = 0; | 
 | int opcode_count = 0; | 
 |  | 
 | /* The set of possible completers for an opcode.  */ | 
 | struct completer_entry | 
 | { | 
 |   /* This entry's index in the ia64_completer_table[] array.  */ | 
 |   int num; | 
 |  | 
 |   /* The name of the completer.  */ | 
 |   struct string_entry *name; | 
 |  | 
 |   /* This entry's parent.  */ | 
 |   struct completer_entry *parent; | 
 |  | 
 |   /* Set if this is a terminal completer (occurs at the end of an | 
 |      opcode).  */ | 
 |   int is_terminal; | 
 |  | 
 |   /* An alternative completer.  */ | 
 |   struct completer_entry *alternative; | 
 |  | 
 |   /* Additional completers that can be appended to this one.  */ | 
 |   struct completer_entry *addl_entries; | 
 |  | 
 |   /* Before compute_completer_bits () is invoked, this contains the actual | 
 |      instruction opcode for this combination of opcode and completers. | 
 |      Afterwards, it contains those bits that are different from its | 
 |      parent opcode.  */ | 
 |   ia64_insn bits; | 
 |  | 
 |   /* Bits set to 1 correspond to those bits in this completer's opcode | 
 |      that are different from its parent completer's opcode (or from | 
 |      the base opcode if the entry is the root of the opcode's completer | 
 |      list).  This field is filled in by compute_completer_bits ().  */ | 
 |   ia64_insn mask; | 
 |  | 
 |   /* Index into the opcode dependency list, or -1 if none.  */ | 
 |   int dependencies; | 
 |  | 
 |   /* Remember the order encountered in the opcode tables.  */ | 
 |   int order; | 
 | }; | 
 |  | 
 | /* One entry in the disassembler name table.  */ | 
 | struct disent | 
 | { | 
 |   /* The index into the ia64_name_dis array for this entry.  */ | 
 |   int ournum; | 
 |  | 
 |   /* The index into the main_table[] array.  */ | 
 |   int insn; | 
 |  | 
 |   /* The disassmbly priority of this entry.  */ | 
 |   int priority; | 
 |  | 
 |   /* The completer_index value for this entry.  */ | 
 |   ci_t completer_index; | 
 |  | 
 |   /* How many other entries share this decode.  */ | 
 |   int nextcnt; | 
 |  | 
 |   /* The next entry sharing the same decode.  */ | 
 |   struct disent *nexte; | 
 |  | 
 |   /* The next entry in the name list.  */ | 
 |   struct disent *next_ent; | 
 | } *disinsntable = NULL; | 
 |  | 
 | /* A state machine that will eventually be used to generate the | 
 |    disassembler table.  */ | 
 | struct bittree | 
 | { | 
 |   struct disent *disent; | 
 |   struct bittree *bits[3]; /* 0, 1, and X (don't care).  */ | 
 |   int bits_to_skip; | 
 |   int skip_flag; | 
 | } *bittree; | 
 |  | 
 | /* The string table contains all opcodes and completers sorted in | 
 |    alphabetical order.  */ | 
 |  | 
 | /* One entry in the string table.  */ | 
 | struct string_entry | 
 | { | 
 |   /* The index in the ia64_strings[] array for this entry.  */ | 
 |   int num; | 
 |   /* And the string.  */ | 
 |   char *s; | 
 | } **string_table = NULL; | 
 |  | 
 | int strtablen = 0; | 
 | int strtabtotlen = 0; | 
 |  | 
 |  | 
 | /* Resource dependency entries.  */ | 
 | struct rdep | 
 | { | 
 |   char *name;                       /* Resource name.  */ | 
 |   unsigned | 
 |     mode:2,                         /* RAW, WAW, or WAR.  */ | 
 |     semantics:3;                    /* Dependency semantics.  */ | 
 |   char *extra;                      /* Additional semantics info.  */ | 
 |   int nchks; | 
 |   int total_chks;                   /* Total #of terminal insns.  */ | 
 |   int *chks;                        /* Insn classes which read (RAW), write | 
 |                                        (WAW), or write (WAR) this rsrc.  */ | 
 |   int *chknotes;                    /* Dependency notes for each class.  */ | 
 |   int nregs; | 
 |   int total_regs;                   /* Total #of terminal insns.  */ | 
 |   int *regs;                        /* Insn class which write (RAW), write2 | 
 |                                        (WAW), or read (WAR) this rsrc.  */ | 
 |   int *regnotes;                    /* Dependency notes for each class.  */ | 
 |  | 
 |   int waw_special;                  /* Special WAW dependency note.  */ | 
 | } **rdeps = NULL; | 
 |  | 
 | static int rdepslen = 0; | 
 | static int rdepstotlen = 0; | 
 |  | 
 | /* Array of all instruction classes.  */ | 
 | struct iclass | 
 | { | 
 |   char *name;                       /* Instruction class name.  */ | 
 |   int is_class;                     /* Is a class, not a terminal.  */ | 
 |   int nsubs; | 
 |   int *subs;                        /* Other classes within this class.  */ | 
 |   int nxsubs; | 
 |   int xsubs[4];                     /* Exclusions.  */ | 
 |   char *comment;                    /* Optional comment.  */ | 
 |   int note;                         /* Optional note.  */ | 
 |   int terminal_resolved;            /* Did we match this with anything?  */ | 
 |   int orphan;                       /* Detect class orphans.  */ | 
 | } **ics = NULL; | 
 |  | 
 | static int iclen = 0; | 
 | static int ictotlen = 0; | 
 |  | 
 | /* An opcode dependency (chk/reg pair of dependency lists).  */ | 
 | struct opdep | 
 | { | 
 |   int chk;                          /* index into dlists */ | 
 |   int reg;                          /* index into dlists */ | 
 | } **opdeps; | 
 |  | 
 | static int opdeplen = 0; | 
 | static int opdeptotlen = 0; | 
 |  | 
 | /* A generic list of dependencies w/notes encoded.  These may be shared.  */ | 
 | struct deplist | 
 | { | 
 |   int len; | 
 |   unsigned short *deps; | 
 | } **dlists; | 
 |  | 
 | static int dlistlen = 0; | 
 | static int dlisttotlen = 0; | 
 |  | 
 |  | 
 | static void fail (const char *, ...) ATTRIBUTE_PRINTF_1; | 
 | static void warn (const char *, ...) ATTRIBUTE_PRINTF_1; | 
 | static struct rdep * insert_resource (const char *, enum ia64_dependency_mode); | 
 | static int  deplist_equals (struct deplist *, struct deplist *); | 
 | static short insert_deplist (int, unsigned short *); | 
 | static short insert_dependencies (int, unsigned short *, int, unsigned short *); | 
 | static void  mark_used (struct iclass *, int); | 
 | static int  fetch_insn_class (const char *, int); | 
 | static int  sub_compare (const void *, const void *); | 
 | static void load_insn_classes (void); | 
 | static void parse_resource_users (const char *, int **, int *, int **); | 
 | static int  parse_semantics (char *); | 
 | static void add_dep (const char *, const char *, const char *, int, int, char *, int); | 
 | static void load_depfile (const char *, enum ia64_dependency_mode); | 
 | static void load_dependencies (void); | 
 | static int  irf_operand (int, const char *); | 
 | static int  in_iclass_mov_x (struct ia64_opcode *, struct iclass *, const char *, const char *); | 
 | static int  in_iclass (struct ia64_opcode *, struct iclass *, const char *, const char *, int *); | 
 | static int  lookup_regindex (const char *, int); | 
 | static int  lookup_specifier (const char *); | 
 | static void print_dependency_table (void); | 
 | static struct string_entry * insert_string (char *); | 
 | static void gen_dis_table (struct bittree *); | 
 | static void print_dis_table (void); | 
 | static void generate_disassembler (void); | 
 | static void print_string_table (void); | 
 | static int  completer_entries_eq (struct completer_entry *, struct completer_entry *); | 
 | static struct completer_entry * insert_gclist (struct completer_entry *); | 
 | static int  get_prefix_len (const char *); | 
 | static void compute_completer_bits (struct main_entry *, struct completer_entry *); | 
 | static void collapse_redundant_completers (void); | 
 | static int  insert_opcode_dependencies (struct ia64_opcode *, struct completer_entry *); | 
 | static void insert_completer_entry (struct ia64_opcode *, struct main_entry *, int); | 
 | static void print_completer_entry (struct completer_entry *); | 
 | static void print_completer_table (void); | 
 | static int  opcodes_eq (struct ia64_opcode *, struct ia64_opcode *); | 
 | static void add_opcode_entry (struct ia64_opcode *); | 
 | static void print_main_table (void); | 
 | static void shrink (struct ia64_opcode *); | 
 | static void print_version (void); | 
 | static void usage (FILE *, int); | 
 | static void finish_distable (void); | 
 | static void insert_bit_table_ent (struct bittree *, int, ia64_insn, ia64_insn, int, int, ci_t); | 
 | static void add_dis_entry (struct bittree *, ia64_insn, ia64_insn, int, struct completer_entry *, ci_t); | 
 | static void compact_distree (struct bittree *); | 
 | static struct bittree * make_bittree_entry (void); | 
 | static struct disent * add_dis_table_ent (struct disent *, int, int, ci_t); | 
 |  | 
 |  | 
 | static void | 
 | fail (const char *message, ...) | 
 | { | 
 |   va_list args; | 
 |  | 
 |   va_start (args, message); | 
 |   fprintf (stderr, _("%s: Error: "), program_name); | 
 |   vfprintf (stderr, message, args); | 
 |   va_end (args); | 
 |   xexit (1); | 
 | } | 
 |  | 
 | static void | 
 | warn (const char *message, ...) | 
 | { | 
 |   va_list args; | 
 |  | 
 |   va_start (args, message); | 
 |  | 
 |   fprintf (stderr, _("%s: Warning: "), program_name); | 
 |   vfprintf (stderr, message, args); | 
 |   va_end (args); | 
 | } | 
 |  | 
 | /* Add NAME to the resource table, where TYPE is RAW or WAW.  */ | 
 | static struct rdep * | 
 | insert_resource (const char *name, enum ia64_dependency_mode type) | 
 | { | 
 |   if (rdepslen == rdepstotlen) | 
 |     { | 
 |       rdepstotlen += 20; | 
 |       rdeps = (struct rdep **) | 
 |         xrealloc (rdeps, sizeof(struct rdep **) * rdepstotlen); | 
 |     } | 
 |   rdeps[rdepslen] = tmalloc(struct rdep); | 
 |   memset((void *)rdeps[rdepslen], 0, sizeof(struct rdep)); | 
 |   rdeps[rdepslen]->name = xstrdup (name); | 
 |   rdeps[rdepslen]->mode = type; | 
 |   rdeps[rdepslen]->waw_special = 0; | 
 |  | 
 |   return rdeps[rdepslen++]; | 
 | } | 
 |  | 
 | /* Are the lists of dependency indexes equivalent?  */ | 
 | static int | 
 | deplist_equals (struct deplist *d1, struct deplist *d2) | 
 | { | 
 |   int i; | 
 |  | 
 |   if (d1->len != d2->len) | 
 |     return 0; | 
 |  | 
 |   for (i = 0; i < d1->len; i++) | 
 |     if (d1->deps[i] != d2->deps[i]) | 
 |       return 0; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Add the list of dependencies to the list of dependency lists.  */ | 
 | static short | 
 | insert_deplist (int count, unsigned short *deps) | 
 | { | 
 |   /* Sort the list, then see if an equivalent list exists already. | 
 |      this results in a much smaller set of dependency lists.  */ | 
 |   struct deplist *list; | 
 |   char set[0x10000]; | 
 |   int i; | 
 |  | 
 |   memset ((void *)set, 0, sizeof (set)); | 
 |   for (i = 0; i < count; i++) | 
 |     set[deps[i]] = 1; | 
 |  | 
 |   count = 0; | 
 |   for (i = 0; i < (int) sizeof (set); i++) | 
 |     if (set[i]) | 
 |       ++count; | 
 |  | 
 |   list = tmalloc (struct deplist); | 
 |   list->len = count; | 
 |   list->deps = (unsigned short *) malloc (sizeof (unsigned short) * count); | 
 |  | 
 |   for (i = 0, count = 0; i < (int) sizeof (set); i++) | 
 |     if (set[i]) | 
 |       list->deps[count++] = i; | 
 |  | 
 |   /* Does this list exist already?  */ | 
 |   for (i = 0; i < dlistlen; i++) | 
 |     if (deplist_equals (list, dlists[i])) | 
 |       { | 
 | 	free (list->deps); | 
 | 	free (list); | 
 | 	return i; | 
 |       } | 
 |  | 
 |   if (dlistlen == dlisttotlen) | 
 |     { | 
 |       dlisttotlen += 20; | 
 |       dlists = (struct deplist **) | 
 |         xrealloc (dlists, sizeof(struct deplist **) * dlisttotlen); | 
 |     } | 
 |   dlists[dlistlen] = list; | 
 |  | 
 |   return dlistlen++; | 
 | } | 
 |  | 
 | /* Add the given pair of dependency lists to the opcode dependency list.  */ | 
 | static short | 
 | insert_dependencies (int nchks, unsigned short *chks, | 
 |                      int nregs, unsigned short *regs) | 
 | { | 
 |   struct opdep *pair; | 
 |   int i; | 
 |   int regind = -1; | 
 |   int chkind = -1; | 
 |  | 
 |   if (nregs > 0) | 
 |     regind = insert_deplist (nregs, regs); | 
 |   if (nchks > 0) | 
 |     chkind = insert_deplist (nchks, chks); | 
 |  | 
 |   for (i = 0; i < opdeplen; i++) | 
 |     if (opdeps[i]->chk == chkind | 
 | 	&& opdeps[i]->reg == regind) | 
 |       return i; | 
 |  | 
 |   pair = tmalloc (struct opdep); | 
 |   pair->chk = chkind; | 
 |   pair->reg = regind; | 
 |  | 
 |   if (opdeplen == opdeptotlen) | 
 |     { | 
 |       opdeptotlen += 20; | 
 |       opdeps = (struct opdep **) | 
 |         xrealloc (opdeps, sizeof(struct opdep **) * opdeptotlen); | 
 |     } | 
 |   opdeps[opdeplen] = pair; | 
 |  | 
 |   return opdeplen++; | 
 | } | 
 |  | 
 | static void | 
 | mark_used (struct iclass *ic, int clear_terminals) | 
 | { | 
 |   int i; | 
 |  | 
 |   ic->orphan = 0; | 
 |   if (clear_terminals) | 
 |     ic->terminal_resolved = 1; | 
 |  | 
 |   for (i = 0; i < ic->nsubs; i++) | 
 |     mark_used (ics[ic->subs[i]], clear_terminals); | 
 |  | 
 |   for (i = 0; i < ic->nxsubs; i++) | 
 |     mark_used (ics[ic->xsubs[i]], clear_terminals); | 
 | } | 
 |  | 
 | /* Look up an instruction class; if CREATE make a new one if none found; | 
 |    returns the index into the insn class array.  */ | 
 | static int | 
 | fetch_insn_class (const char *full_name, int create) | 
 | { | 
 |   char *name; | 
 |   char *notestr; | 
 |   char *xsect; | 
 |   char *comment; | 
 |   int i, note = 0; | 
 |   int ind; | 
 |   int is_class = 0; | 
 |  | 
 |   if (startswith (full_name, "IC:")) | 
 |     { | 
 |       name = xstrdup (full_name + 3); | 
 |       is_class = 1; | 
 |     } | 
 |   else | 
 |     name = xstrdup (full_name); | 
 |  | 
 |   if ((xsect = strchr(name, '\\')) != NULL) | 
 |     is_class = 1; | 
 |   if ((comment = strchr(name, '[')) != NULL) | 
 |     is_class = 1; | 
 |   if ((notestr = strchr(name, '+')) != NULL) | 
 |     is_class = 1; | 
 |  | 
 |   /* If it is a composite class, then ignore comments and notes that come after | 
 |      the '\\', since they don't apply to the part we are decoding now.  */ | 
 |   if (xsect) | 
 |     { | 
 |       if (comment > xsect) | 
 | 	comment = 0; | 
 |       if (notestr > xsect) | 
 | 	notestr = 0; | 
 |     } | 
 |  | 
 |   if (notestr) | 
 |     { | 
 |       char *nextnotestr; | 
 |  | 
 |       note = atoi (notestr + 1); | 
 |       if ((nextnotestr = strchr (notestr + 1, '+')) != NULL) | 
 |         { | 
 |           if (strcmp (notestr, "+1+13") == 0) | 
 |             note = 13; | 
 |           else if (!xsect || nextnotestr < xsect) | 
 |             warn (_("multiple note %s not handled\n"), notestr); | 
 |         } | 
 |     } | 
 |  | 
 |   /* If it's a composite class, leave the notes and comments in place so that | 
 |      we have a unique name for the composite class.  Otherwise, we remove | 
 |      them.  */ | 
 |   if (!xsect) | 
 |     { | 
 |       if (notestr) | 
 |         *notestr = 0; | 
 |       if (comment) | 
 |         *comment = 0; | 
 |     } | 
 |  | 
 |   for (i = 0; i < iclen; i++) | 
 |     if (strcmp (name, ics[i]->name) == 0 | 
 |         && ((comment == NULL && ics[i]->comment == NULL) | 
 |             || (comment != NULL && ics[i]->comment != NULL | 
 |                 && strncmp (ics[i]->comment, comment, | 
 |                             strlen (ics[i]->comment)) == 0)) | 
 |         && note == ics[i]->note) | 
 |       return i; | 
 |  | 
 |   if (!create) | 
 |     return -1; | 
 |  | 
 |   /* Doesn't exist, so make a new one.  */ | 
 |   if (iclen == ictotlen) | 
 |     { | 
 |       ictotlen += 20; | 
 |       ics = (struct iclass **) | 
 |         xrealloc (ics, (ictotlen) * sizeof (struct iclass *)); | 
 |     } | 
 |  | 
 |   ind = iclen++; | 
 |   ics[ind] = tmalloc (struct iclass); | 
 |   memset ((void *)ics[ind], 0, sizeof (struct iclass)); | 
 |   ics[ind]->name = xstrdup (name); | 
 |   ics[ind]->is_class = is_class; | 
 |   ics[ind]->orphan = 1; | 
 |  | 
 |   if (comment) | 
 |     { | 
 |       ics[ind]->comment = xstrdup (comment + 1); | 
 |       ics[ind]->comment[strlen (ics[ind]->comment)-1] = 0; | 
 |     } | 
 |  | 
 |   if (notestr) | 
 |     ics[ind]->note = note; | 
 |  | 
 |   /* If it's a composite class, there's a comment or note, look for an | 
 |      existing class or terminal with the same name.  */ | 
 |   if ((xsect || comment || notestr) && is_class) | 
 |     { | 
 |       /* First, populate with the class we're based on.  */ | 
 |       char *subname = name; | 
 |  | 
 |       if (xsect) | 
 |         *xsect = 0; | 
 |       else if (comment) | 
 |         *comment = 0; | 
 |       else if (notestr) | 
 |         *notestr = 0; | 
 |  | 
 |       ics[ind]->nsubs = 1; | 
 |       ics[ind]->subs = tmalloc(int); | 
 |       ics[ind]->subs[0] = fetch_insn_class (subname, 1); | 
 |     } | 
 |  | 
 |   while (xsect) | 
 |     { | 
 |       char *subname = xsect + 1; | 
 |  | 
 |       xsect = strchr (subname, '\\'); | 
 |       if (xsect) | 
 |         *xsect = 0; | 
 |       ics[ind]->xsubs[ics[ind]->nxsubs] = fetch_insn_class (subname,1); | 
 |       ics[ind]->nxsubs++; | 
 |     } | 
 |   free (name); | 
 |  | 
 |   return ind; | 
 | } | 
 |  | 
 | /* For sorting a class's sub-class list only; make sure classes appear before | 
 |    terminals.  */ | 
 | static int | 
 | sub_compare (const void *e1, const void *e2) | 
 | { | 
 |   struct iclass *ic1 = ics[*(int *)e1]; | 
 |   struct iclass *ic2 = ics[*(int *)e2]; | 
 |  | 
 |   if (ic1->is_class) | 
 |     { | 
 |       if (!ic2->is_class) | 
 |         return -1; | 
 |     } | 
 |   else if (ic2->is_class) | 
 |     return 1; | 
 |  | 
 |   return strcmp (ic1->name, ic2->name); | 
 | } | 
 |  | 
 | static void | 
 | load_insn_classes (void) | 
 | { | 
 |   FILE *fp = fopen ("ia64-ic.tbl", "r"); | 
 |   char buf[2048]; | 
 |  | 
 |   if (fp == NULL) | 
 |     fail (_("can't find ia64-ic.tbl for reading\n")); | 
 |  | 
 |   /* Discard first line.  */ | 
 |   if (fgets (buf, sizeof(buf), fp) == NULL) | 
 |     return; | 
 |  | 
 |   while (!feof (fp)) | 
 |     { | 
 |       int iclass; | 
 |       char *name; | 
 |       char *tmp; | 
 |  | 
 |       if (fgets (buf, sizeof (buf), fp) == NULL) | 
 |         break; | 
 |  | 
 |       while (ISSPACE (buf[strlen (buf) - 1])) | 
 |         buf[strlen (buf) - 1] = '\0'; | 
 |  | 
 |       name = tmp = buf; | 
 |       while (*tmp != ';') | 
 |         { | 
 |           ++tmp; | 
 |           if (tmp == buf + sizeof (buf)) | 
 |             abort (); | 
 |         } | 
 |       *tmp++ = '\0'; | 
 |  | 
 |       iclass = fetch_insn_class (name, 1); | 
 |       ics[iclass]->is_class = 1; | 
 |  | 
 |       if (strcmp (name, "none") == 0) | 
 |         { | 
 |           ics[iclass]->is_class = 0; | 
 |           ics[iclass]->terminal_resolved = 1; | 
 |           continue; | 
 |         } | 
 |  | 
 |       /* For this class, record all sub-classes.  */ | 
 |       while (*tmp) | 
 |         { | 
 |           char *subname; | 
 |           int sub; | 
 |  | 
 |           while (*tmp && ISSPACE (*tmp)) | 
 |             { | 
 |               ++tmp; | 
 |               if (tmp == buf + sizeof (buf)) | 
 |                 abort (); | 
 |             } | 
 |           subname = tmp; | 
 |           while (*tmp && *tmp != ',') | 
 |             { | 
 |               ++tmp; | 
 |               if (tmp == buf + sizeof (buf)) | 
 |                 abort (); | 
 |             } | 
 |           if (*tmp == ',') | 
 |             *tmp++ = '\0'; | 
 |  | 
 |           ics[iclass]->subs = (int *) | 
 |             xrealloc ((void *)ics[iclass]->subs, | 
 | 		      (ics[iclass]->nsubs + 1) * sizeof (int)); | 
 |  | 
 |           sub = fetch_insn_class (subname, 1); | 
 |           ics[iclass]->subs = (int *) | 
 |             xrealloc (ics[iclass]->subs, (ics[iclass]->nsubs + 1) * sizeof (int)); | 
 |           ics[iclass]->subs[ics[iclass]->nsubs++] = sub; | 
 |         } | 
 |  | 
 |       /* Make sure classes come before terminals.  */ | 
 |       qsort ((void *)ics[iclass]->subs, | 
 |              ics[iclass]->nsubs, sizeof(int), sub_compare); | 
 |     } | 
 |   fclose (fp); | 
 |  | 
 |   if (debug) | 
 |     printf ("%d classes\n", iclen); | 
 | } | 
 |  | 
 | /* Extract the insn classes from the given line.  */ | 
 | static void | 
 | parse_resource_users (const char *ref, int **usersp, int *nusersp, | 
 |                       int **notesp) | 
 | { | 
 |   int c; | 
 |   char *line = xstrdup (ref); | 
 |   char *tmp = line; | 
 |   int *users = *usersp; | 
 |   int count = *nusersp; | 
 |   int *notes = *notesp; | 
 |  | 
 |   c = *tmp; | 
 |   while (c != 0) | 
 |     { | 
 |       char *notestr; | 
 |       int note; | 
 |       char *xsect; | 
 |       int iclass; | 
 |       int create = 0; | 
 |       char *name; | 
 |  | 
 |       while (ISSPACE (*tmp)) | 
 |         ++tmp; | 
 |       name = tmp; | 
 |       while (*tmp && *tmp != ',') | 
 |         ++tmp; | 
 |       c = *tmp; | 
 |       *tmp++ = '\0'; | 
 |  | 
 |       xsect = strchr (name, '\\'); | 
 |       if ((notestr = strstr (name, "+")) != NULL) | 
 |         { | 
 |           char *nextnotestr; | 
 |  | 
 |           note = atoi (notestr + 1); | 
 |           if ((nextnotestr = strchr (notestr + 1, '+')) != NULL) | 
 |             { | 
 |               /* Note 13 always implies note 1.  */ | 
 |               if (strcmp (notestr, "+1+13") == 0) | 
 |                 note = 13; | 
 |               else if (!xsect || nextnotestr < xsect) | 
 |                 warn (_("multiple note %s not handled\n"), notestr); | 
 |             } | 
 |           if (!xsect) | 
 |             *notestr = '\0'; | 
 |         } | 
 |       else | 
 |         note = 0; | 
 |  | 
 |       /* All classes are created when the insn class table is parsed; | 
 |          Individual instructions might not appear until the dependency tables | 
 |          are read.  Only create new classes if it's *not* an insn class, | 
 |          or if it's a composite class (which wouldn't necessarily be in the IC | 
 |          table).  */ | 
 |       if (! startswith (name, "IC:") || xsect != NULL) | 
 |         create = 1; | 
 |  | 
 |       iclass = fetch_insn_class (name, create); | 
 |       if (iclass != -1) | 
 |         { | 
 |           users = (int *) | 
 |             xrealloc ((void *) users,(count + 1) * sizeof (int)); | 
 |           notes = (int *) | 
 |             xrealloc ((void *) notes,(count + 1) * sizeof (int)); | 
 |           notes[count] = note; | 
 |           users[count++] = iclass; | 
 |           mark_used (ics[iclass], 0); | 
 |         } | 
 |       else if (debug) | 
 | 	printf("Class %s not found\n", name); | 
 |     } | 
 |   /* Update the return values.  */ | 
 |   *usersp = users; | 
 |   *nusersp = count; | 
 |   *notesp = notes; | 
 |  | 
 |   free (line); | 
 | } | 
 |  | 
 | static int | 
 | parse_semantics (char *sem) | 
 | { | 
 |   if (strcmp (sem, "none") == 0) | 
 |     return IA64_DVS_NONE; | 
 |   else if (strcmp (sem, "implied") == 0) | 
 |     return IA64_DVS_IMPLIED; | 
 |   else if (strcmp (sem, "impliedF") == 0) | 
 |     return IA64_DVS_IMPLIEDF; | 
 |   else if (strcmp (sem, "data") == 0) | 
 |     return IA64_DVS_DATA; | 
 |   else if (strcmp (sem, "instr") == 0) | 
 |     return IA64_DVS_INSTR; | 
 |   else if (strcmp (sem, "specific") == 0) | 
 |     return IA64_DVS_SPECIFIC; | 
 |   else if (strcmp (sem, "stop") == 0) | 
 |     return IA64_DVS_STOP; | 
 |   else | 
 |     return IA64_DVS_OTHER; | 
 | } | 
 |  | 
 | static void | 
 | add_dep (const char *name, const char *chk, const char *reg, | 
 |          int semantics, int mode, char *extra, int flag) | 
 | { | 
 |   struct rdep *rs; | 
 |  | 
 |   rs = insert_resource (name, mode); | 
 |  | 
 |   parse_resource_users (chk, &rs->chks, &rs->nchks, &rs->chknotes); | 
 |   parse_resource_users (reg, &rs->regs, &rs->nregs, &rs->regnotes); | 
 |  | 
 |   rs->semantics = semantics; | 
 |   rs->extra = extra; | 
 |   rs->waw_special = flag; | 
 | } | 
 |  | 
 | static void | 
 | load_depfile (const char *filename, enum ia64_dependency_mode mode) | 
 | { | 
 |   FILE *fp = fopen (filename, "r"); | 
 |   char buf[1024]; | 
 |  | 
 |   if (fp == NULL) | 
 |     fail (_("can't find %s for reading\n"), filename); | 
 |  | 
 |   if (fgets (buf, sizeof(buf), fp) == NULL) | 
 |     return; | 
 |   while (!feof (fp)) | 
 |     { | 
 |       char *name, *tmp; | 
 |       int semantics; | 
 |       char *extra; | 
 |       char *regp, *chkp; | 
 |  | 
 |       if (fgets (buf, sizeof(buf), fp) == NULL) | 
 |         break; | 
 |  | 
 |       while (ISSPACE (buf[strlen (buf) - 1])) | 
 |         buf[strlen (buf) - 1] = '\0'; | 
 |  | 
 |       name = tmp = buf; | 
 |       while (*tmp != ';') | 
 |         ++tmp; | 
 |       *tmp++ = '\0'; | 
 |  | 
 |       while (ISSPACE (*tmp)) | 
 |         ++tmp; | 
 |       regp = tmp; | 
 |       tmp = strchr (tmp, ';'); | 
 |       if (!tmp) | 
 |         abort (); | 
 |       *tmp++ = 0; | 
 |       while (ISSPACE (*tmp)) | 
 |         ++tmp; | 
 |       chkp = tmp; | 
 |       tmp = strchr (tmp, ';'); | 
 |       if (!tmp) | 
 |         abort (); | 
 |       *tmp++ = 0; | 
 |       while (ISSPACE (*tmp)) | 
 |         ++tmp; | 
 |       semantics = parse_semantics (tmp); | 
 |       extra = semantics == IA64_DVS_OTHER ? xstrdup (tmp) : NULL; | 
 |  | 
 |       /* For WAW entries, if the chks and regs differ, we need to enter the | 
 |          entries in both positions so that the tables will be parsed properly, | 
 |          without a lot of extra work.  */ | 
 |       if (mode == IA64_DV_WAW && strcmp (regp, chkp) != 0) | 
 |         { | 
 |           add_dep (name, chkp, regp, semantics, mode, extra, 0); | 
 |           add_dep (name, regp, chkp, semantics, mode, extra, 1); | 
 |         } | 
 |       else | 
 |         { | 
 |           add_dep (name, chkp, regp, semantics, mode, extra, 0); | 
 |         } | 
 |     } | 
 |   fclose (fp); | 
 | } | 
 |  | 
 | static void | 
 | load_dependencies (void) | 
 | { | 
 |   load_depfile ("ia64-raw.tbl", IA64_DV_RAW); | 
 |   load_depfile ("ia64-waw.tbl", IA64_DV_WAW); | 
 |   load_depfile ("ia64-war.tbl", IA64_DV_WAR); | 
 |  | 
 |   if (debug) | 
 |     printf ("%d RAW/WAW/WAR dependencies\n", rdepslen); | 
 | } | 
 |  | 
 | /* Is the given operand an indirect register file operand?  */ | 
 | static int | 
 | irf_operand (int op, const char *field) | 
 | { | 
 |   if (!field) | 
 |     { | 
 |       return op == IA64_OPND_RR_R3 || op == IA64_OPND_DBR_R3 | 
 |         || op == IA64_OPND_IBR_R3  || op == IA64_OPND_PKR_R3 | 
 | 	|| op == IA64_OPND_PMC_R3  || op == IA64_OPND_PMD_R3 | 
 | 	|| op == IA64_OPND_MSR_R3 || op == IA64_OPND_CPUID_R3; | 
 |     } | 
 |   else | 
 |     { | 
 |       return ((op == IA64_OPND_RR_R3 && strstr (field, "rr")) | 
 |               || (op == IA64_OPND_DBR_R3 && strstr (field, "dbr")) | 
 |               || (op == IA64_OPND_IBR_R3 && strstr (field, "ibr")) | 
 |               || (op == IA64_OPND_PKR_R3 && strstr (field, "pkr")) | 
 |               || (op == IA64_OPND_PMC_R3 && strstr (field, "pmc")) | 
 |               || (op == IA64_OPND_PMD_R3 && strstr (field, "pmd")) | 
 |               || (op == IA64_OPND_MSR_R3 && strstr (field, "msr")) | 
 |               || (op == IA64_OPND_CPUID_R3 && strstr (field, "cpuid")) | 
 |               || (op == IA64_OPND_DAHR_R3  && strstr (field, "dahr"))); | 
 |     } | 
 | } | 
 |  | 
 | /* Handle mov_ar, mov_br, mov_cr, move_dahr, mov_indirect, mov_ip, mov_pr, | 
 |  * mov_psr, and  mov_um insn classes.  */ | 
 | static int | 
 | in_iclass_mov_x (struct ia64_opcode *idesc, struct iclass *ic, | 
 |                  const char *format, const char *field) | 
 | { | 
 |   int plain_mov = strcmp (idesc->name, "mov") == 0; | 
 |  | 
 |   if (!format) | 
 |     return 0; | 
 |  | 
 |   switch (ic->name[4]) | 
 |     { | 
 |     default: | 
 |       abort (); | 
 |     case 'a': | 
 |       { | 
 |         int i = strcmp (idesc->name, "mov.i") == 0; | 
 |         int m = strcmp (idesc->name, "mov.m") == 0; | 
 |         int i2627 = i && idesc->operands[0] == IA64_OPND_AR3; | 
 |         int i28 = i && idesc->operands[1] == IA64_OPND_AR3; | 
 |         int m2930 = m && idesc->operands[0] == IA64_OPND_AR3; | 
 |         int m31 = m && idesc->operands[1] == IA64_OPND_AR3; | 
 |         int pseudo0 = plain_mov && idesc->operands[1] == IA64_OPND_AR3; | 
 |         int pseudo1 = plain_mov && idesc->operands[0] == IA64_OPND_AR3; | 
 |  | 
 |         /* IC:mov ar */ | 
 |         if (i2627) | 
 |           return strstr (format, "I26") || strstr (format, "I27"); | 
 |         if (i28) | 
 |           return strstr (format, "I28") != NULL; | 
 |         if (m2930) | 
 |           return strstr (format, "M29") || strstr (format, "M30"); | 
 |         if (m31) | 
 |           return strstr (format, "M31") != NULL; | 
 |         if (pseudo0 || pseudo1) | 
 |           return 1; | 
 |       } | 
 |       break; | 
 |     case 'b': | 
 |       { | 
 |         int i21 = idesc->operands[0] == IA64_OPND_B1; | 
 |         int i22 = plain_mov && idesc->operands[1] == IA64_OPND_B2; | 
 |         if (i22) | 
 |           return strstr (format, "I22") != NULL; | 
 |         if (i21) | 
 |           return strstr (format, "I21") != NULL; | 
 |       } | 
 |       break; | 
 |     case 'c': | 
 |       { | 
 |         int m32 = plain_mov && idesc->operands[0] == IA64_OPND_CR3; | 
 |         int m33 = plain_mov && idesc->operands[1] == IA64_OPND_CR3; | 
 |         if (m32) | 
 |           return strstr (format, "M32") != NULL; | 
 |         if (m33) | 
 |           return strstr (format, "M33") != NULL; | 
 |       } | 
 |       break; | 
 |     case 'd': | 
 |       { | 
 |         int m50 = plain_mov && idesc->operands[0] == IA64_OPND_DAHR3; | 
 |         if (m50) | 
 |           return strstr (format, "M50") != NULL; | 
 |       } | 
 |       break; | 
 |     case 'i': | 
 |       if (ic->name[5] == 'n') | 
 |         { | 
 |           int m42 = plain_mov && irf_operand (idesc->operands[0], field); | 
 |           int m43 = plain_mov && irf_operand (idesc->operands[1], field); | 
 |           if (m42) | 
 |             return strstr (format, "M42") != NULL; | 
 |           if (m43) | 
 |             return strstr (format, "M43") != NULL; | 
 |         } | 
 |       else if (ic->name[5] == 'p') | 
 |         { | 
 |           return idesc->operands[1] == IA64_OPND_IP; | 
 |         } | 
 |       else | 
 |         abort (); | 
 |       break; | 
 |     case 'p': | 
 |       if (ic->name[5] == 'r') | 
 |         { | 
 |           int i25 = plain_mov && idesc->operands[1] == IA64_OPND_PR; | 
 |           int i23 = plain_mov && idesc->operands[0] == IA64_OPND_PR; | 
 |           int i24 = plain_mov && idesc->operands[0] == IA64_OPND_PR_ROT; | 
 |           if (i23) | 
 |             return strstr (format, "I23") != NULL; | 
 |           if (i24) | 
 |             return strstr (format, "I24") != NULL; | 
 |           if (i25) | 
 |             return strstr (format, "I25") != NULL; | 
 |         } | 
 |       else if (ic->name[5] == 's') | 
 |         { | 
 |           int m35 = plain_mov && idesc->operands[0] == IA64_OPND_PSR_L; | 
 |           int m36 = plain_mov && idesc->operands[1] == IA64_OPND_PSR; | 
 |           if (m35) | 
 |             return strstr (format, "M35") != NULL; | 
 |           if (m36) | 
 |             return strstr (format, "M36") != NULL; | 
 |         } | 
 |       else | 
 |         abort (); | 
 |       break; | 
 |     case 'u': | 
 |       { | 
 |         int m35 = plain_mov && idesc->operands[0] == IA64_OPND_PSR_UM; | 
 |         int m36 = plain_mov && idesc->operands[1] == IA64_OPND_PSR_UM; | 
 |         if (m35) | 
 |           return strstr (format, "M35") != NULL; | 
 |         if (m36) | 
 |           return strstr (format, "M36") != NULL; | 
 |       } | 
 |       break; | 
 |     } | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Is the given opcode in the given insn class?  */ | 
 | static int | 
 | in_iclass (struct ia64_opcode *idesc, struct iclass *ic, | 
 | 	   const char *format, const char *field, int *notep) | 
 | { | 
 |   int i; | 
 |   int resolved = 0; | 
 |  | 
 |   if (ic->comment) | 
 |     { | 
 |       if (startswith (ic->comment, "Format")) | 
 |         { | 
 |           /* Assume that the first format seen is the most restrictive, and | 
 |              only keep a later one if it looks like it's more restrictive.  */ | 
 |           if (format) | 
 |             { | 
 |               if (strlen (ic->comment) < strlen (format)) | 
 |                 { | 
 |                   warn (_("most recent format '%s'\nappears more restrictive than '%s'\n"), | 
 | 			ic->comment, format); | 
 |                   format = ic->comment; | 
 |                 } | 
 |             } | 
 |           else | 
 |             format = ic->comment; | 
 |         } | 
 |       else if (startswith (ic->comment, "Field")) | 
 |         { | 
 |           if (field) | 
 |             warn (_("overlapping field %s->%s\n"), | 
 | 		  ic->comment, field); | 
 |           field = ic->comment; | 
 |         } | 
 |     } | 
 |  | 
 |   /* An insn class matches anything that is the same followed by completers, | 
 |      except when the absence and presence of completers constitutes different | 
 |      instructions.  */ | 
 |   if (ic->nsubs == 0 && ic->nxsubs == 0) | 
 |     { | 
 |       int is_mov = startswith (idesc->name, "mov"); | 
 |       int plain_mov = strcmp (idesc->name, "mov") == 0; | 
 |       int len = strlen(ic->name); | 
 |  | 
 |       resolved = ((strncmp (ic->name, idesc->name, len) == 0) | 
 |                   && (idesc->name[len] == '\0' | 
 |                       || idesc->name[len] == '.')); | 
 |  | 
 |       /* All break, nop, and hint variations must match exactly.  */ | 
 |       if (resolved && | 
 |           (strcmp (ic->name, "break") == 0 | 
 |            || strcmp (ic->name, "nop") == 0 | 
 | 	   || strcmp (ic->name, "hint") == 0)) | 
 |         resolved = strcmp (ic->name, idesc->name) == 0; | 
 |  | 
 |       /* Assume restrictions in the FORMAT/FIELD negate resolution, | 
 |          unless specifically allowed by clauses in this block.  */ | 
 |       if (resolved && field) | 
 |         { | 
 |           /* Check Field(sf)==sN against opcode sN.  */ | 
 |           if (strstr(field, "(sf)==") != NULL) | 
 |             { | 
 |               char *sf; | 
 |  | 
 |               if ((sf = strstr (idesc->name, ".s")) != 0) | 
 | 		resolved = strcmp (sf + 1, strstr (field, "==") + 2) == 0; | 
 |             } | 
 |           /* Check Field(lftype)==XXX.  */ | 
 |           else if (strstr (field, "(lftype)") != NULL) | 
 |             { | 
 |               if (strstr (idesc->name, "fault") != NULL) | 
 |                 resolved = strstr (field, "fault") != NULL; | 
 |               else | 
 |                 resolved = strstr (field, "fault") == NULL; | 
 |             } | 
 |           /* Handle Field(ctype)==XXX.  */ | 
 |           else if (strstr (field, "(ctype)") != NULL) | 
 |             { | 
 |               if (strstr (idesc->name, "or.andcm")) | 
 |                 resolved = strstr (field, "or.andcm") != NULL; | 
 |               else if (strstr (idesc->name, "and.orcm")) | 
 |                 resolved = strstr (field, "and.orcm") != NULL; | 
 |               else if (strstr (idesc->name, "orcm")) | 
 |                 resolved = strstr (field, "or orcm") != NULL; | 
 |               else if (strstr (idesc->name, "or")) | 
 |                 resolved = strstr (field, "or orcm") != NULL; | 
 |               else if (strstr (idesc->name, "andcm")) | 
 |                 resolved = strstr (field, "and andcm") != NULL; | 
 |               else if (strstr (idesc->name, "and")) | 
 |                 resolved = strstr (field, "and andcm") != NULL; | 
 |               else if (strstr (idesc->name, "unc")) | 
 |                 resolved = strstr (field, "unc") != NULL; | 
 |               else | 
 |                 resolved = strcmp (field, "Field(ctype)==") == 0; | 
 |             } | 
 |         } | 
 |  | 
 |       if (resolved && format) | 
 |         { | 
 |           if (startswith (idesc->name, "dep") | 
 |                    && strstr (format, "I13") != NULL) | 
 |             resolved = idesc->operands[1] == IA64_OPND_IMM8; | 
 |           else if (startswith (idesc->name, "chk") | 
 |                    && strstr (format, "M21") != NULL) | 
 |             resolved = idesc->operands[0] == IA64_OPND_F2; | 
 |           else if (startswith (idesc->name, "lfetch")) | 
 |             resolved = (strstr (format, "M14 M15") != NULL | 
 |                         && (idesc->operands[1] == IA64_OPND_R2 | 
 |                             || idesc->operands[1] == IA64_OPND_IMM9b)); | 
 |           else if (startswith (idesc->name, "br.call") | 
 |                    && strstr (format, "B5") != NULL) | 
 |             resolved = idesc->operands[1] == IA64_OPND_B2; | 
 |           else if (startswith (idesc->name, "br.call") | 
 |                    && strstr (format, "B3") != NULL) | 
 |             resolved = idesc->operands[1] == IA64_OPND_TGT25c; | 
 |           else if (startswith (idesc->name, "brp") | 
 |                    && strstr (format, "B7") != NULL) | 
 |             resolved = idesc->operands[0] == IA64_OPND_B2; | 
 |           else if (strcmp (ic->name, "invala") == 0) | 
 |             resolved = strcmp (idesc->name, ic->name) == 0; | 
 | 	  else if (startswith (idesc->name, "st") | 
 | 		   && (strstr (format, "M5") != NULL | 
 | 		       || strstr (format, "M10") != NULL)) | 
 | 	    resolved = idesc->flags & IA64_OPCODE_POSTINC; | 
 | 	  else if (startswith (idesc->name, "ld") | 
 | 		   && (strstr (format, "M2 M3") != NULL | 
 | 		       || strstr (format, "M12") != NULL | 
 | 		       || strstr (format, "M7 M8") != NULL)) | 
 | 	    resolved = idesc->flags & IA64_OPCODE_POSTINC; | 
 |           else | 
 |             resolved = 0; | 
 |         } | 
 |  | 
 |       /* Misc brl variations ('.cond' is optional); | 
 |          plain brl matches brl.cond.  */ | 
 |       if (!resolved | 
 |           && (strcmp (idesc->name, "brl") == 0 | 
 |               || startswith (idesc->name, "brl.")) | 
 |           && strcmp (ic->name, "brl.cond") == 0) | 
 |         { | 
 |           resolved = 1; | 
 |         } | 
 |  | 
 |       /* Misc br variations ('.cond' is optional).  */ | 
 |       if (!resolved | 
 |           && (strcmp (idesc->name, "br") == 0 | 
 |               || startswith (idesc->name, "br.")) | 
 |           && strcmp (ic->name, "br.cond") == 0) | 
 |         { | 
 |           if (format) | 
 |             resolved = (strstr (format, "B4") != NULL | 
 |                         && idesc->operands[0] == IA64_OPND_B2) | 
 |               || (strstr (format, "B1") != NULL | 
 |                   && idesc->operands[0] == IA64_OPND_TGT25c); | 
 |           else | 
 |             resolved = 1; | 
 |         } | 
 |  | 
 |       /* probe variations.  */ | 
 |       if (!resolved && startswith (idesc->name, "probe")) | 
 |         { | 
 |           resolved = strcmp (ic->name, "probe") == 0 | 
 |             && !((strstr (idesc->name, "fault") != NULL) | 
 |                  ^ (format && strstr (format, "M40") != NULL)); | 
 |         } | 
 |  | 
 |       /* mov variations.  */ | 
 |       if (!resolved && is_mov) | 
 |         { | 
 |           if (plain_mov) | 
 |             { | 
 |               /* mov alias for fmerge.  */ | 
 |               if (strcmp (ic->name, "fmerge") == 0) | 
 |                 { | 
 |                   resolved = idesc->operands[0] == IA64_OPND_F1 | 
 |                     && idesc->operands[1] == IA64_OPND_F3; | 
 |                 } | 
 |               /* mov alias for adds (r3 or imm14).  */ | 
 |               else if (strcmp (ic->name, "adds") == 0) | 
 |                 { | 
 |                   resolved = (idesc->operands[0] == IA64_OPND_R1 | 
 |                               && (idesc->operands[1] == IA64_OPND_R3 | 
 |                                   || (idesc->operands[1] == IA64_OPND_IMM14))); | 
 |                 } | 
 |               /* mov alias for addl.  */ | 
 |               else if (strcmp (ic->name, "addl") == 0) | 
 |                 { | 
 |                   resolved = idesc->operands[0] == IA64_OPND_R1 | 
 |                     && idesc->operands[1] == IA64_OPND_IMM22; | 
 |                 } | 
 |             } | 
 |  | 
 |           /* Some variants of mov and mov.[im].  */ | 
 |           if (!resolved && startswith (ic->name, "mov_")) | 
 | 	    resolved = in_iclass_mov_x (idesc, ic, format, field); | 
 |         } | 
 |  | 
 |       /* Keep track of this so we can flag any insn classes which aren't | 
 |          mapped onto at least one real insn.  */ | 
 |       if (resolved) | 
 | 	ic->terminal_resolved = 1; | 
 |     } | 
 |   else for (i = 0; i < ic->nsubs; i++) | 
 |     { | 
 |       if (in_iclass (idesc, ics[ic->subs[i]], format, field, notep)) | 
 |         { | 
 |           int j; | 
 |  | 
 |           for (j = 0; j < ic->nxsubs; j++) | 
 | 	    if (in_iclass (idesc, ics[ic->xsubs[j]], NULL, NULL, NULL)) | 
 | 	      return 0; | 
 |  | 
 |           if (debug > 1) | 
 |             printf ("%s is in IC %s\n", idesc->name, ic->name); | 
 |  | 
 |           resolved = 1; | 
 |           break; | 
 |         } | 
 |     } | 
 |  | 
 |   /* If it's in this IC, add the IC note (if any) to the insn.  */ | 
 |   if (resolved) | 
 |     { | 
 |       if (ic->note && notep) | 
 |         { | 
 |           if (*notep && *notep != ic->note) | 
 | 	    warn (_("overwriting note %d with note %d (IC:%s)\n"), | 
 | 		  *notep, ic->note, ic->name); | 
 |  | 
 |           *notep = ic->note; | 
 |         } | 
 |     } | 
 |  | 
 |   return resolved; | 
 | } | 
 |  | 
 |  | 
 | static int | 
 | lookup_regindex (const char *name, int specifier) | 
 | { | 
 |   switch (specifier) | 
 |     { | 
 |     case IA64_RS_ARX: | 
 |       if (strstr (name, "[RSC]")) | 
 |         return 16; | 
 |       if (strstr (name, "[BSP]")) | 
 |         return 17; | 
 |       else if (strstr (name, "[BSPSTORE]")) | 
 |         return 18; | 
 |       else if (strstr (name, "[RNAT]")) | 
 |         return 19; | 
 |       else if (strstr (name, "[FCR]")) | 
 |         return 21; | 
 |       else if (strstr (name, "[EFLAG]")) | 
 |         return 24; | 
 |       else if (strstr (name, "[CSD]")) | 
 |         return 25; | 
 |       else if (strstr (name, "[SSD]")) | 
 |         return 26; | 
 |       else if (strstr (name, "[CFLG]")) | 
 |         return 27; | 
 |       else if (strstr (name, "[FSR]")) | 
 |         return 28; | 
 |       else if (strstr (name, "[FIR]")) | 
 |         return 29; | 
 |       else if (strstr (name, "[FDR]")) | 
 |         return 30; | 
 |       else if (strstr (name, "[CCV]")) | 
 |         return 32; | 
 |       else if (strstr (name, "[ITC]")) | 
 |         return 44; | 
 |       else if (strstr (name, "[RUC]")) | 
 |         return 45; | 
 |       else if (strstr (name, "[PFS]")) | 
 |         return 64; | 
 |       else if (strstr (name, "[LC]")) | 
 |         return 65; | 
 |       else if (strstr (name, "[EC]")) | 
 |         return 66; | 
 |       abort (); | 
 |     case IA64_RS_CRX: | 
 |       if (strstr (name, "[DCR]")) | 
 |         return 0; | 
 |       else if (strstr (name, "[ITM]")) | 
 |         return 1; | 
 |       else if (strstr (name, "[IVA]")) | 
 |         return 2; | 
 |       else if (strstr (name, "[PTA]")) | 
 |         return 8; | 
 |       else if (strstr (name, "[GPTA]")) | 
 |         return 9; | 
 |       else if (strstr (name, "[IPSR]")) | 
 |         return 16; | 
 |       else if (strstr (name, "[ISR]")) | 
 |         return 17; | 
 |       else if (strstr (name, "[IIP]")) | 
 |         return 19; | 
 |       else if (strstr (name, "[IFA]")) | 
 |         return 20; | 
 |       else if (strstr (name, "[ITIR]")) | 
 |         return 21; | 
 |       else if (strstr (name, "[IIPA]")) | 
 |         return 22; | 
 |       else if (strstr (name, "[IFS]")) | 
 |         return 23; | 
 |       else if (strstr (name, "[IIM]")) | 
 |         return 24; | 
 |       else if (strstr (name, "[IHA]")) | 
 |         return 25; | 
 |       else if (strstr (name, "[LID]")) | 
 |         return 64; | 
 |       else if (strstr (name, "[IVR]")) | 
 |         return 65; | 
 |       else if (strstr (name, "[TPR]")) | 
 |         return 66; | 
 |       else if (strstr (name, "[EOI]")) | 
 |         return 67; | 
 |       else if (strstr (name, "[ITV]")) | 
 |         return 72; | 
 |       else if (strstr (name, "[PMV]")) | 
 |         return 73; | 
 |       else if (strstr (name, "[CMCV]")) | 
 |         return 74; | 
 |       abort (); | 
 |     case IA64_RS_PSR: | 
 |       if (strstr (name, ".be")) | 
 |         return 1; | 
 |       else if (strstr (name, ".up")) | 
 |         return 2; | 
 |       else if (strstr (name, ".ac")) | 
 |         return 3; | 
 |       else if (strstr (name, ".mfl")) | 
 |         return 4; | 
 |       else if (strstr (name, ".mfh")) | 
 |         return 5; | 
 |       else if (strstr (name, ".ic")) | 
 |         return 13; | 
 |       else if (strstr (name, ".i")) | 
 |         return 14; | 
 |       else if (strstr (name, ".pk")) | 
 |         return 15; | 
 |       else if (strstr (name, ".dt")) | 
 |         return 17; | 
 |       else if (strstr (name, ".dfl")) | 
 |         return 18; | 
 |       else if (strstr (name, ".dfh")) | 
 |         return 19; | 
 |       else if (strstr (name, ".sp")) | 
 |         return 20; | 
 |       else if (strstr (name, ".pp")) | 
 |         return 21; | 
 |       else if (strstr (name, ".di")) | 
 |         return 22; | 
 |       else if (strstr (name, ".si")) | 
 |         return 23; | 
 |       else if (strstr (name, ".db")) | 
 |         return 24; | 
 |       else if (strstr (name, ".lp")) | 
 |         return 25; | 
 |       else if (strstr (name, ".tb")) | 
 |         return 26; | 
 |       else if (strstr (name, ".rt")) | 
 |         return 27; | 
 |       else if (strstr (name, ".cpl")) | 
 |         return 32; | 
 |       else if (strstr (name, ".rs")) | 
 |         return 34; | 
 |       else if (strstr (name, ".mc")) | 
 |         return 35; | 
 |       else if (strstr (name, ".it")) | 
 |         return 36; | 
 |       else if (strstr (name, ".id")) | 
 |         return 37; | 
 |       else if (strstr (name, ".da")) | 
 |         return 38; | 
 |       else if (strstr (name, ".dd")) | 
 |         return 39; | 
 |       else if (strstr (name, ".ss")) | 
 |         return 40; | 
 |       else if (strstr (name, ".ri")) | 
 |         return 41; | 
 |       else if (strstr (name, ".ed")) | 
 |         return 43; | 
 |       else if (strstr (name, ".bn")) | 
 |         return 44; | 
 |       else if (strstr (name, ".ia")) | 
 |         return 45; | 
 |       else if (strstr (name, ".vm")) | 
 |         return 46; | 
 |       else | 
 |         abort (); | 
 |     default: | 
 |       break; | 
 |     } | 
 |   return REG_NONE; | 
 | } | 
 |  | 
 | static int | 
 | lookup_specifier (const char *name) | 
 | { | 
 |   if (strchr (name, '%')) | 
 |     { | 
 |       if (strstr (name, "AR[K%]") != NULL) | 
 |         return IA64_RS_AR_K; | 
 |       if (strstr (name, "AR[UNAT]") != NULL) | 
 |         return IA64_RS_AR_UNAT; | 
 |       if (strstr (name, "AR%, % in 8") != NULL) | 
 |         return IA64_RS_AR; | 
 |       if (strstr (name, "AR%, % in 48") != NULL) | 
 |         return IA64_RS_ARb; | 
 |       if (strstr (name, "BR%") != NULL) | 
 |         return IA64_RS_BR; | 
 |       if (strstr (name, "CR[IIB%]") != NULL) | 
 |         return IA64_RS_CR_IIB; | 
 |       if (strstr (name, "CR[IRR%]") != NULL) | 
 |         return IA64_RS_CR_IRR; | 
 |       if (strstr (name, "CR[LRR%]") != NULL) | 
 |         return IA64_RS_CR_LRR; | 
 |       if (strstr (name, "CR%") != NULL) | 
 |         return IA64_RS_CR; | 
 |       if (strstr (name, "DAHR%, % in 0") != NULL) | 
 |         return IA64_RS_DAHR; | 
 |       if (strstr (name, "FR%, % in 0") != NULL) | 
 |         return IA64_RS_FR; | 
 |       if (strstr (name, "FR%, % in 2") != NULL) | 
 |         return IA64_RS_FRb; | 
 |       if (strstr (name, "GR%") != NULL) | 
 |         return IA64_RS_GR; | 
 |       if (strstr (name, "PR%, % in 1 ") != NULL) | 
 |         return IA64_RS_PR; | 
 |       if (strstr (name, "PR%, % in 16 ") != NULL) | 
 | 	return IA64_RS_PRr; | 
 |  | 
 |       warn (_("don't know how to specify %% dependency %s\n"), | 
 | 	    name); | 
 |     } | 
 |   else if (strchr (name, '#')) | 
 |     { | 
 |       if (strstr (name, "CPUID#") != NULL) | 
 |         return IA64_RS_CPUID; | 
 |       if (strstr (name, "DBR#") != NULL) | 
 |         return IA64_RS_DBR; | 
 |       if (strstr (name, "IBR#") != NULL) | 
 |         return IA64_RS_IBR; | 
 |       if (strstr (name, "MSR#") != NULL) | 
 | 	return IA64_RS_MSR; | 
 |       if (strstr (name, "PKR#") != NULL) | 
 |         return IA64_RS_PKR; | 
 |       if (strstr (name, "PMC#") != NULL) | 
 |         return IA64_RS_PMC; | 
 |       if (strstr (name, "PMD#") != NULL) | 
 |         return IA64_RS_PMD; | 
 |       if (strstr (name, "RR#") != NULL) | 
 |         return IA64_RS_RR; | 
 |  | 
 |       warn (_("Don't know how to specify # dependency %s\n"), | 
 | 	    name); | 
 |     } | 
 |   else if (startswith (name, "AR[FPSR]")) | 
 |     return IA64_RS_AR_FPSR; | 
 |   else if (startswith (name, "AR[")) | 
 |     return IA64_RS_ARX; | 
 |   else if (startswith (name, "CR[")) | 
 |     return IA64_RS_CRX; | 
 |   else if (startswith (name, "PSR.")) | 
 |     return IA64_RS_PSR; | 
 |   else if (strcmp (name, "InService*") == 0) | 
 |     return IA64_RS_INSERVICE; | 
 |   else if (strcmp (name, "GR0") == 0) | 
 |     return IA64_RS_GR0; | 
 |   else if (strcmp (name, "CFM") == 0) | 
 |     return IA64_RS_CFM; | 
 |   else if (strcmp (name, "PR63") == 0) | 
 |     return IA64_RS_PR63; | 
 |   else if (strcmp (name, "RSE") == 0) | 
 |     return IA64_RS_RSE; | 
 |  | 
 |   return IA64_RS_ANY; | 
 | } | 
 |  | 
 | static void | 
 | print_dependency_table (void) | 
 | { | 
 |   int i, j; | 
 |  | 
 |   if (debug) | 
 |     { | 
 |       for (i=0;i < iclen;i++) | 
 |         { | 
 |           if (ics[i]->is_class) | 
 |             { | 
 |               if (!ics[i]->nsubs) | 
 |                 { | 
 |                   if (ics[i]->comment) | 
 | 		    warn (_("IC:%s [%s] has no terminals or sub-classes\n"), | 
 | 			  ics[i]->name, ics[i]->comment); | 
 | 		  else | 
 | 		    warn (_("IC:%s has no terminals or sub-classes\n"), | 
 | 			  ics[i]->name); | 
 |                 } | 
 |             } | 
 |           else | 
 |             { | 
 |               if (!ics[i]->terminal_resolved && !ics[i]->orphan) | 
 |                 { | 
 |                   if (ics[i]->comment) | 
 | 		    warn (_("no insns mapped directly to terminal IC %s [%s]"), | 
 | 			  ics[i]->name, ics[i]->comment); | 
 | 		  else | 
 | 		    warn (_("no insns mapped directly to terminal IC %s\n"), | 
 | 			  ics[i]->name); | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |       for (i = 0; i < iclen; i++) | 
 |         { | 
 |           if (ics[i]->orphan) | 
 |             { | 
 |               mark_used (ics[i], 1); | 
 |               warn (_("class %s is defined but not used\n"), | 
 | 		    ics[i]->name); | 
 |             } | 
 |         } | 
 |  | 
 |       if (debug > 1) | 
 | 	for (i = 0; i < rdepslen; i++) | 
 | 	  { | 
 | 	    static const char *mode_str[] = { "RAW", "WAW", "WAR" }; | 
 |  | 
 | 	    if (rdeps[i]->total_chks == 0) | 
 | 	      { | 
 | 		if (rdeps[i]->total_regs) | 
 | 		  warn (_("Warning: rsrc %s (%s) has no chks\n"), | 
 | 			rdeps[i]->name, mode_str[rdeps[i]->mode]); | 
 | 		else | 
 | 		  warn (_("Warning: rsrc %s (%s) has no chks or regs\n"), | 
 | 			rdeps[i]->name, mode_str[rdeps[i]->mode]); | 
 | 	      } | 
 | 	    else if (rdeps[i]->total_regs == 0) | 
 | 	      warn (_("rsrc %s (%s) has no regs\n"), | 
 | 		    rdeps[i]->name, mode_str[rdeps[i]->mode]); | 
 | 	  } | 
 |     } | 
 |  | 
 |   /* The dependencies themselves.  */ | 
 |   printf ("static const struct ia64_dependency\ndependencies[] = {\n"); | 
 |   for (i = 0; i < rdepslen; i++) | 
 |     { | 
 |       /* '%', '#', AR[], CR[], or PSR. indicates we need to specify the actual | 
 |          resource used.  */ | 
 |       int specifier = lookup_specifier (rdeps[i]->name); | 
 |       int regindex = lookup_regindex (rdeps[i]->name, specifier); | 
 |  | 
 |       printf ("  { \"%s\", %d, %d, %d, %d, ", | 
 |               rdeps[i]->name, specifier, | 
 |               (int)rdeps[i]->mode, (int)rdeps[i]->semantics, regindex); | 
 |       if (rdeps[i]->semantics == IA64_DVS_OTHER) | 
 | 	{ | 
 | 	  const char *quote, *rest; | 
 |  | 
 | 	  putchar ('\"'); | 
 | 	  rest = rdeps[i]->extra; | 
 | 	  quote = strchr (rest, '\"'); | 
 | 	  while (quote != NULL) | 
 | 	    { | 
 | 	      printf ("%.*s\\\"", (int) (quote - rest), rest); | 
 | 	      rest = quote + 1; | 
 | 	      quote = strchr (rest, '\"'); | 
 | 	    } | 
 | 	  printf ("%s\", ", rest); | 
 | 	} | 
 |       else | 
 | 	printf ("NULL, "); | 
 |       printf("},\n"); | 
 |     } | 
 |   printf ("};\n\n"); | 
 |  | 
 |   /* And dependency lists.  */ | 
 |   for (i=0;i < dlistlen;i++) | 
 |     { | 
 |       unsigned int len = (unsigned) -1; | 
 |       printf ("static const unsigned short dep%d[] = {", i); | 
 |       for (j=0;j < dlists[i]->len; j++) | 
 |         { | 
 |           if (len > 74) | 
 |             { | 
 |               printf("\n "); | 
 |               len = 1; | 
 |             } | 
 |           len += printf (" %d,", dlists[i]->deps[j]); | 
 |         } | 
 |       printf ("\n};\n\n"); | 
 |     } | 
 |  | 
 |   /* And opcode dependency list.  */ | 
 |   printf ("#define NELS(X) (sizeof(X)/sizeof(X[0]))\n"); | 
 |   printf ("static const struct ia64_opcode_dependency\n"); | 
 |   printf ("op_dependencies[] = {\n"); | 
 |   for (i = 0; i < opdeplen; i++) | 
 |     { | 
 |       printf ("  { "); | 
 |       if (opdeps[i]->chk == -1) | 
 |         printf ("0, NULL, "); | 
 |       else | 
 |         printf ("NELS(dep%d), dep%d, ", opdeps[i]->chk, opdeps[i]->chk); | 
 |       if (opdeps[i]->reg == -1) | 
 |         printf ("0, NULL, "); | 
 |       else | 
 |         printf ("NELS(dep%d), dep%d, ", opdeps[i]->reg, opdeps[i]->reg); | 
 |       printf ("},\n"); | 
 |     } | 
 |   printf ("};\n\n"); | 
 | } | 
 |  | 
 |  | 
 | /* Add STR to the string table.  */ | 
 | static struct string_entry * | 
 | insert_string (char *str) | 
 | { | 
 |   int start = 0, end = strtablen; | 
 |   int i, x; | 
 |  | 
 |   if (strtablen == strtabtotlen) | 
 |     { | 
 |       strtabtotlen += 20; | 
 |       string_table = (struct string_entry **) | 
 | 	xrealloc (string_table, | 
 | 		  sizeof (struct string_entry **) * strtabtotlen); | 
 |     } | 
 |  | 
 |   if (strtablen == 0) | 
 |     { | 
 |       strtablen = 1; | 
 |       string_table[0] = tmalloc (struct string_entry); | 
 |       string_table[0]->s = xstrdup (str); | 
 |       string_table[0]->num = 0; | 
 |       return string_table[0]; | 
 |     } | 
 |  | 
 |   if (strcmp (str, string_table[strtablen - 1]->s) > 0) | 
 |     i = end; | 
 |   else if (strcmp (str, string_table[0]->s) < 0) | 
 |     i = 0; | 
 |   else | 
 |     { | 
 |       while (1) | 
 | 	{ | 
 | 	  int c; | 
 |  | 
 | 	  i = (start + end) / 2; | 
 | 	  c = strcmp (str, string_table[i]->s); | 
 |  | 
 | 	  if (c < 0) | 
 | 	    end = i - 1; | 
 | 	  else if (c == 0) | 
 | 	    return string_table[i]; | 
 | 	  else | 
 | 	    start = i + 1; | 
 |  | 
 | 	  if (start > end) | 
 | 	    break; | 
 | 	} | 
 |     } | 
 |  | 
 |   for (; i > 0 && i < strtablen; i--) | 
 |     if (strcmp (str, string_table[i - 1]->s) > 0) | 
 |       break; | 
 |  | 
 |   for (; i < strtablen; i++) | 
 |     if (strcmp (str, string_table[i]->s) < 0) | 
 |       break; | 
 |  | 
 |   for (x = strtablen - 1; x >= i; x--) | 
 |     { | 
 |       string_table[x + 1] = string_table[x]; | 
 |       string_table[x + 1]->num = x + 1; | 
 |     } | 
 |  | 
 |   string_table[i] = tmalloc (struct string_entry); | 
 |   string_table[i]->s = xstrdup (str); | 
 |   string_table[i]->num = i; | 
 |   strtablen++; | 
 |  | 
 |   return string_table[i]; | 
 | } | 
 |  | 
 | static struct bittree * | 
 | make_bittree_entry (void) | 
 | { | 
 |   struct bittree *res = tmalloc (struct bittree); | 
 |  | 
 |   res->disent = NULL; | 
 |   res->bits[0] = NULL; | 
 |   res->bits[1] = NULL; | 
 |   res->bits[2] = NULL; | 
 |   res->skip_flag = 0; | 
 |   res->bits_to_skip = 0; | 
 |   return res; | 
 | } | 
 |  | 
 |  | 
 | static struct disent * | 
 | add_dis_table_ent (struct disent *which, int insn, int order, | 
 |                    ci_t completer_index) | 
 | { | 
 |   int ci = 0; | 
 |   struct disent *ent; | 
 |  | 
 |   if (which != NULL) | 
 |     { | 
 |       ent = which; | 
 |  | 
 |       ent->nextcnt++; | 
 |       while (ent->nexte != NULL) | 
 | 	ent = ent->nexte; | 
 |  | 
 |       ent = (ent->nexte = tmalloc (struct disent)); | 
 |     } | 
 |   else | 
 |     { | 
 |       ent = tmalloc (struct disent); | 
 |       ent->next_ent = disinsntable; | 
 |       disinsntable = ent; | 
 |       which = ent; | 
 |     } | 
 |   ent->nextcnt = 0; | 
 |   ent->nexte = NULL; | 
 |   ent->insn = insn; | 
 |   ent->priority = order; | 
 |  | 
 |   while (completer_index != 1) | 
 |     { | 
 |       ci = (ci << 1) | (completer_index & 1); | 
 |       completer_index >>= 1; | 
 |     } | 
 |   ent->completer_index = ci; | 
 |   return which; | 
 | } | 
 |  | 
 | static void | 
 | finish_distable (void) | 
 | { | 
 |   struct disent *ent = disinsntable; | 
 |   struct disent *prev = ent; | 
 |  | 
 |   ent->ournum = 32768; | 
 |   while ((ent = ent->next_ent) != NULL) | 
 |     { | 
 |       ent->ournum = prev->ournum + prev->nextcnt + 1; | 
 |       prev = ent; | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | insert_bit_table_ent (struct bittree *curr_ent, int bit, ia64_insn opcode, | 
 |                       ia64_insn mask, int opcodenum, int order, | 
 |                       ci_t completer_index) | 
 | { | 
 |   ia64_insn m; | 
 |   int b; | 
 |   struct bittree *next; | 
 |  | 
 |   if (bit == -1) | 
 |     { | 
 |       struct disent *nent = add_dis_table_ent (curr_ent->disent, | 
 |                                                opcodenum, order, | 
 | 					       completer_index); | 
 |       curr_ent->disent = nent; | 
 |       return; | 
 |     } | 
 |  | 
 |   m = ((ia64_insn) 1) << bit; | 
 |  | 
 |   if (mask & m) | 
 |     b = (opcode & m) ? 1 : 0; | 
 |   else | 
 |     b = 2; | 
 |  | 
 |   next = curr_ent->bits[b]; | 
 |   if (next == NULL) | 
 |     { | 
 |       next = make_bittree_entry (); | 
 |       curr_ent->bits[b] = next; | 
 |     } | 
 |   insert_bit_table_ent (next, bit - 1, opcode, mask, opcodenum, order, | 
 | 			completer_index); | 
 | } | 
 |  | 
 | static void | 
 | add_dis_entry (struct bittree *first, ia64_insn opcode, ia64_insn mask, | 
 |                int opcodenum, struct completer_entry *ent, ci_t completer_index) | 
 | { | 
 |   if (completer_index & ((ci_t)1 << 32) ) | 
 |     abort (); | 
 |  | 
 |   while (ent != NULL) | 
 |     { | 
 |       ia64_insn newopcode = (opcode & (~ ent->mask)) | ent->bits; | 
 |       add_dis_entry (first, newopcode, mask, opcodenum, ent->addl_entries, | 
 | 		     (completer_index << 1) | 1); | 
 |  | 
 |       if (ent->is_terminal) | 
 | 	{ | 
 | 	  insert_bit_table_ent (bittree, 40, newopcode, mask, | 
 |                                 opcodenum, opcode_count - ent->order - 1, | 
 | 				(completer_index << 1) | 1); | 
 | 	} | 
 |       completer_index <<= 1; | 
 |       ent = ent->alternative; | 
 |     } | 
 | } | 
 |  | 
 | /* This optimization pass combines multiple "don't care" nodes.  */ | 
 | static void | 
 | compact_distree (struct bittree *ent) | 
 | { | 
 | #define IS_SKIP(ent) \ | 
 |     ((ent->bits[2] !=NULL) \ | 
 |      && (ent->bits[0] == NULL && ent->bits[1] == NULL && ent->skip_flag == 0)) | 
 |  | 
 |   int bitcnt = 0; | 
 |   struct bittree *nent = ent; | 
 |   int x; | 
 |  | 
 |   while (IS_SKIP (nent)) | 
 |     { | 
 |       bitcnt++; | 
 |       nent = nent->bits[2]; | 
 |     } | 
 |  | 
 |   if (bitcnt) | 
 |     { | 
 |       struct bittree *next = ent->bits[2]; | 
 |  | 
 |       ent->bits[0] = nent->bits[0]; | 
 |       ent->bits[1] = nent->bits[1]; | 
 |       ent->bits[2] = nent->bits[2]; | 
 |       ent->disent = nent->disent; | 
 |       ent->skip_flag = 1; | 
 |       ent->bits_to_skip = bitcnt; | 
 |       while (next != nent) | 
 | 	{ | 
 | 	  struct bittree *b = next; | 
 | 	  next = next->bits[2]; | 
 | 	  free (b); | 
 | 	} | 
 |       free (nent); | 
 |     } | 
 |  | 
 |   for (x = 0; x < 3; x++) | 
 |     { | 
 |       struct bittree *i = ent->bits[x]; | 
 |  | 
 |       if (i != NULL) | 
 | 	compact_distree (i); | 
 |     } | 
 | } | 
 |  | 
 | static unsigned char *insn_list; | 
 | static int insn_list_len = 0; | 
 | static int tot_insn_list_len = 0; | 
 |  | 
 | /* Generate the disassembler state machine corresponding to the tree | 
 |    in ENT.  */ | 
 | static void | 
 | gen_dis_table (struct bittree *ent) | 
 | { | 
 |   int x; | 
 |   int our_offset = insn_list_len; | 
 |   int bitsused = 5; | 
 |   int totbits = bitsused; | 
 |   int needed_bytes; | 
 |   int zero_count = 0; | 
 |   int zero_dest = 0;	/* Initialize this with 0 to keep gcc quiet...  */ | 
 |  | 
 |   /* If this is a terminal entry, there's no point in skipping any | 
 |      bits.  */ | 
 |   if (ent->skip_flag && ent->bits[0] == NULL && ent->bits[1] == NULL && | 
 |       ent->bits[2] == NULL) | 
 |     { | 
 |       if (ent->disent == NULL) | 
 | 	abort (); | 
 |       else | 
 | 	ent->skip_flag = 0; | 
 |     } | 
 |  | 
 |   /* Calculate the amount of space needed for this entry, or at least | 
 |      a conservatively large approximation.  */ | 
 |   if (ent->skip_flag) | 
 |     totbits += 5; | 
 |  | 
 |   for (x = 1; x < 3; x++) | 
 |     if (ent->bits[x] != NULL) | 
 |       totbits += 16; | 
 |  | 
 |   if (ent->disent != NULL) | 
 |     { | 
 |       if (ent->bits[2] != NULL) | 
 | 	abort (); | 
 |  | 
 |       totbits += 16; | 
 |     } | 
 |  | 
 |   /* Now allocate the space.  */ | 
 |   needed_bytes = (totbits + 7) / 8; | 
 |   if ((needed_bytes + insn_list_len) > tot_insn_list_len) | 
 |     { | 
 |       tot_insn_list_len += 256; | 
 |       insn_list = (unsigned char *) xrealloc (insn_list, tot_insn_list_len); | 
 |     } | 
 |   our_offset = insn_list_len; | 
 |   insn_list_len += needed_bytes; | 
 |   memset (insn_list + our_offset, 0, needed_bytes); | 
 |  | 
 |   /* Encode the skip entry by setting bit 6 set in the state op field, | 
 |      and store the # of bits to skip immediately after.  */ | 
 |   if (ent->skip_flag) | 
 |     { | 
 |       bitsused += 5; | 
 |       insn_list[our_offset + 0] |= 0x40 | ((ent->bits_to_skip >> 2) & 0xf); | 
 |       insn_list[our_offset + 1] |= ((ent->bits_to_skip & 3) << 6); | 
 |     } | 
 |  | 
 | #define IS_ONLY_IFZERO(ENT) \ | 
 |   ((ENT)->bits[0] != NULL && (ENT)->bits[1] == NULL && (ENT)->bits[2] == NULL \ | 
 |    && (ENT)->disent == NULL && (ENT)->skip_flag == 0) | 
 |  | 
 |   /* Store an "if (bit is zero)" instruction by setting bit 7 in the | 
 |      state op field.  */ | 
 |   if (ent->bits[0] != NULL) | 
 |     { | 
 |       struct bittree *nent = ent->bits[0]; | 
 |       zero_count = 0; | 
 |  | 
 |       insn_list[our_offset] |= 0x80; | 
 |  | 
 |       /* We can encode sequences of multiple "if (bit is zero)" tests | 
 | 	 by storing the # of zero bits to check in the lower 3 bits of | 
 | 	 the instruction.  However, this only applies if the state | 
 | 	 solely tests for a zero bit.  */ | 
 |  | 
 |       if (IS_ONLY_IFZERO (ent)) | 
 | 	{ | 
 | 	  while (IS_ONLY_IFZERO (nent) && zero_count < 7) | 
 | 	    { | 
 | 	      nent = nent->bits[0]; | 
 | 	      zero_count++; | 
 | 	    } | 
 |  | 
 | 	  insn_list[our_offset + 0] |= zero_count; | 
 | 	} | 
 |       zero_dest = insn_list_len; | 
 |       gen_dis_table (nent); | 
 |     } | 
 |  | 
 |   /* Now store the remaining tests.  We also handle a sole "termination | 
 |      entry" by storing it as an "any bit" test.  */ | 
 |  | 
 |   for (x = 1; x < 3; x++) | 
 |     { | 
 |       if (ent->bits[x] != NULL || (x == 2 && ent->disent != NULL)) | 
 | 	{ | 
 | 	  struct bittree *i = ent->bits[x]; | 
 | 	  int idest; | 
 | 	  int currbits = 15; | 
 |  | 
 | 	  if (i != NULL) | 
 | 	    { | 
 | 	      /* If the instruction being branched to only consists of | 
 | 		 a termination entry, use the termination entry as the | 
 | 		 place to branch to instead.  */ | 
 | 	      if (i->bits[0] == NULL && i->bits[1] == NULL | 
 | 		  && i->bits[2] == NULL && i->disent != NULL) | 
 | 		{ | 
 | 		  idest = i->disent->ournum; | 
 | 		  i = NULL; | 
 | 		} | 
 | 	      else | 
 | 		idest = insn_list_len - our_offset; | 
 | 	    } | 
 | 	  else | 
 | 	    idest = ent->disent->ournum; | 
 |  | 
 | 	  /* If the destination offset for the if (bit is 1) test is less | 
 | 	     than 256 bytes away, we can store it as 8-bits instead of 16; | 
 | 	     the instruction has bit 5 set for the 16-bit address, and bit | 
 | 	     4 for the 8-bit address.  Since we've already allocated 16 | 
 | 	     bits for the address we need to deallocate the space. | 
 |  | 
 | 	     Note that branchings within the table are relative, and | 
 | 	     there are no branches that branch past our instruction yet | 
 | 	     so we do not need to adjust any other offsets.  */ | 
 | 	  if (x == 1) | 
 | 	    { | 
 | 	      if (idest <= 256) | 
 | 		{ | 
 | 		  int start = our_offset + bitsused / 8 + 1; | 
 |  | 
 | 		  memmove (insn_list + start, | 
 | 			   insn_list + start + 1, | 
 | 			   insn_list_len - (start + 1)); | 
 | 		  currbits = 7; | 
 | 		  totbits -= 8; | 
 | 		  needed_bytes--; | 
 | 		  insn_list_len--; | 
 | 		  insn_list[our_offset] |= 0x10; | 
 | 		  idest--; | 
 | 		} | 
 | 	      else | 
 | 		insn_list[our_offset] |= 0x20; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* An instruction which solely consists of a termination | 
 | 		 marker and whose disassembly name index is < 4096 | 
 | 		 can be stored in 16 bits.  The encoding is slightly | 
 | 		 odd; the upper 4 bits of the instruction are 0x3, and | 
 | 		 bit 3 loses its normal meaning.  */ | 
 |  | 
 | 	      if (ent->bits[0] == NULL && ent->bits[1] == NULL | 
 | 		  && ent->bits[2] == NULL && ent->skip_flag == 0 | 
 | 		  && ent->disent != NULL | 
 | 		  && ent->disent->ournum < (32768 + 4096)) | 
 | 		{ | 
 | 		  int start = our_offset + bitsused / 8 + 1; | 
 |  | 
 | 		  memmove (insn_list + start, | 
 | 			   insn_list + start + 1, | 
 | 			   insn_list_len - (start + 1)); | 
 | 		  currbits = 11; | 
 | 		  totbits -= 5; | 
 | 		  bitsused--; | 
 | 		  needed_bytes--; | 
 | 		  insn_list_len--; | 
 | 		  insn_list[our_offset] |= 0x30; | 
 | 		  idest &= ~32768; | 
 | 		} | 
 | 	      else | 
 | 		insn_list[our_offset] |= 0x08; | 
 | 	    } | 
 |  | 
 | 	  if (debug) | 
 | 	    { | 
 | 	      int id = idest; | 
 |  | 
 | 	      if (i == NULL) | 
 | 		id |= 32768; | 
 | 	      else if (! (id & 32768)) | 
 | 		id += our_offset; | 
 |  | 
 | 	      if (x == 1) | 
 | 		printf ("%d: if (1) goto %d\n", our_offset, id); | 
 | 	      else | 
 | 		printf ("%d: try %d\n", our_offset, id); | 
 | 	    } | 
 |  | 
 | 	  /* Store the address of the entry being branched to.  */ | 
 | 	  while (currbits >= 0) | 
 | 	    { | 
 | 	      unsigned char *byte = insn_list + our_offset + bitsused / 8; | 
 |  | 
 | 	      if (idest & (1 << currbits)) | 
 | 		*byte |= (1 << (7 - (bitsused % 8))); | 
 |  | 
 | 	      bitsused++; | 
 | 	      currbits--; | 
 | 	    } | 
 |  | 
 | 	  /* Now generate the states for the entry being branched to.  */ | 
 | 	  if (i != NULL) | 
 | 	    gen_dis_table (i); | 
 | 	} | 
 |     } | 
 |  | 
 |   if (debug) | 
 |     { | 
 |       if (ent->skip_flag) | 
 | 	printf ("%d: skipping %d\n", our_offset, ent->bits_to_skip); | 
 |  | 
 |       if (ent->bits[0] != NULL) | 
 | 	printf ("%d: if (0:%d) goto %d\n", our_offset, zero_count + 1, | 
 | 		zero_dest); | 
 |     } | 
 |  | 
 |   if (bitsused != totbits) | 
 |     abort (); | 
 | } | 
 |  | 
 | static void | 
 | print_dis_table (void) | 
 | { | 
 |   int x; | 
 |   struct disent *cent = disinsntable; | 
 |  | 
 |   printf ("static const char dis_table[] = {"); | 
 |   for (x = 0; x < insn_list_len; x++) | 
 |     { | 
 |       if (x % 12 == 0) | 
 | 	printf ("\n "); | 
 |  | 
 |       printf (" 0x%02x,", insn_list[x]); | 
 |     } | 
 |   printf ("\n};\n\n"); | 
 |  | 
 |   printf ("static const struct ia64_dis_names ia64_dis_names[] = {\n"); | 
 |   while (cent != NULL) | 
 |     { | 
 |       struct disent *ent = cent; | 
 |  | 
 |       while (ent != NULL) | 
 | 	{ | 
 | 	  printf ("{ 0x%lx, %d, %d, %d },\n", ( long ) ent->completer_index, | 
 | 		  ent->insn, (ent->nexte != NULL ? 1 : 0), | 
 |                   ent->priority); | 
 | 	  ent = ent->nexte; | 
 | 	} | 
 |       cent = cent->next_ent; | 
 |     } | 
 |   printf ("};\n\n"); | 
 | } | 
 |  | 
 | static void | 
 | generate_disassembler (void) | 
 | { | 
 |   int i; | 
 |  | 
 |   bittree = make_bittree_entry (); | 
 |  | 
 |   for (i = 0; i < otlen; i++) | 
 |     { | 
 |       struct main_entry *ptr = ordered_table[i]; | 
 |  | 
 |       if (ptr->opcode->type != IA64_TYPE_DYN) | 
 | 	add_dis_entry (bittree, | 
 | 		       ptr->opcode->opcode, ptr->opcode->mask, | 
 | 		       ptr->main_index, | 
 | 		       ptr->completers, 1); | 
 |     } | 
 |  | 
 |   compact_distree (bittree); | 
 |   finish_distable (); | 
 |   gen_dis_table (bittree); | 
 |  | 
 |   print_dis_table (); | 
 | } | 
 |  | 
 | static void | 
 | print_string_table (void) | 
 | { | 
 |   int x; | 
 |   char lbuf[80], buf[80]; | 
 |   int blen = 0; | 
 |  | 
 |   printf ("static const char * const ia64_strings[] = {\n"); | 
 |   lbuf[0] = '\0'; | 
 |  | 
 |   for (x = 0; x < strtablen; x++) | 
 |     { | 
 |       int len; | 
 |  | 
 |       if (strlen (string_table[x]->s) > 75) | 
 | 	abort (); | 
 |  | 
 |       sprintf (buf, " \"%s\",", string_table[x]->s); | 
 |       len = strlen (buf); | 
 |  | 
 |       if ((blen + len) > 75) | 
 | 	{ | 
 | 	  printf (" %s\n", lbuf); | 
 | 	  lbuf[0] = '\0'; | 
 | 	  blen = 0; | 
 | 	} | 
 |       strcat (lbuf, buf); | 
 |       blen += len; | 
 |     } | 
 |  | 
 |   if (blen > 0) | 
 |     printf (" %s\n", lbuf); | 
 |  | 
 |   printf ("};\n\n"); | 
 | } | 
 |  | 
 | static struct completer_entry **glist; | 
 | static int glistlen = 0; | 
 | static int glisttotlen = 0; | 
 |  | 
 | /* If the completer trees ENT1 and ENT2 are equal, return 1.  */ | 
 |  | 
 | static int | 
 | completer_entries_eq (struct completer_entry *ent1, | 
 |                       struct completer_entry *ent2) | 
 | { | 
 |   while (ent1 != NULL && ent2 != NULL) | 
 |     { | 
 |       if (ent1->name->num != ent2->name->num | 
 | 	  || ent1->bits != ent2->bits | 
 | 	  || ent1->mask != ent2->mask | 
 | 	  || ent1->is_terminal != ent2->is_terminal | 
 |           || ent1->dependencies != ent2->dependencies | 
 |           || ent1->order != ent2->order) | 
 | 	return 0; | 
 |  | 
 |       if (! completer_entries_eq (ent1->addl_entries, ent2->addl_entries)) | 
 | 	return 0; | 
 |  | 
 |       ent1 = ent1->alternative; | 
 |       ent2 = ent2->alternative; | 
 |     } | 
 |  | 
 |   return ent1 == ent2; | 
 | } | 
 |  | 
 | /* Insert ENT into the global list of completers and return it.  If an | 
 |    equivalent entry (according to completer_entries_eq) already exists, | 
 |    it is returned instead.  */ | 
 | static struct completer_entry * | 
 | insert_gclist (struct completer_entry *ent) | 
 | { | 
 |   if (ent != NULL) | 
 |     { | 
 |       int i; | 
 |       int x; | 
 |       int start = 0, end; | 
 |  | 
 |       ent->addl_entries = insert_gclist (ent->addl_entries); | 
 |       ent->alternative = insert_gclist (ent->alternative); | 
 |  | 
 |       i = glistlen / 2; | 
 |       end = glistlen; | 
 |  | 
 |       if (glisttotlen == glistlen) | 
 | 	{ | 
 | 	  glisttotlen += 20; | 
 | 	  glist = (struct completer_entry **) | 
 | 	    xrealloc (glist, sizeof (struct completer_entry *) * glisttotlen); | 
 | 	} | 
 |  | 
 |       if (glistlen == 0) | 
 | 	{ | 
 | 	  glist[0] = ent; | 
 | 	  glistlen = 1; | 
 | 	  return ent; | 
 | 	} | 
 |  | 
 |       if (ent->name->num < glist[0]->name->num) | 
 | 	i = 0; | 
 |       else if (ent->name->num > glist[end - 1]->name->num) | 
 | 	i = end; | 
 |       else | 
 | 	{ | 
 | 	  int c; | 
 |  | 
 | 	  while (1) | 
 | 	    { | 
 | 	      i = (start + end) / 2; | 
 | 	      c = ent->name->num - glist[i]->name->num; | 
 |  | 
 | 	      if (c < 0) | 
 | 		end = i - 1; | 
 | 	      else if (c == 0) | 
 | 		{ | 
 | 		  while (i > 0 | 
 | 			 && ent->name->num == glist[i - 1]->name->num) | 
 | 		    i--; | 
 |  | 
 | 		  break; | 
 | 		} | 
 | 	      else | 
 | 		start = i + 1; | 
 |  | 
 | 	      if (start > end) | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	  if (c == 0) | 
 | 	    { | 
 | 	      while (i < glistlen) | 
 | 		{ | 
 | 		  if (ent->name->num != glist[i]->name->num) | 
 | 		    break; | 
 |  | 
 | 		  if (completer_entries_eq (ent, glist[i])) | 
 | 		    return glist[i]; | 
 |  | 
 | 		  i++; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |  | 
 |       for (; i > 0 && i < glistlen; i--) | 
 | 	if (ent->name->num >= glist[i - 1]->name->num) | 
 | 	  break; | 
 |  | 
 |       for (; i < glistlen; i++) | 
 | 	if (ent->name->num < glist[i]->name->num) | 
 | 	  break; | 
 |  | 
 |       for (x = glistlen - 1; x >= i; x--) | 
 | 	glist[x + 1] = glist[x]; | 
 |  | 
 |       glist[i] = ent; | 
 |       glistlen++; | 
 |     } | 
 |   return ent; | 
 | } | 
 |  | 
 | static int | 
 | get_prefix_len (const char *name) | 
 | { | 
 |   char *c; | 
 |  | 
 |   if (name[0] == '\0') | 
 |     return 0; | 
 |  | 
 |   c = strchr (name, '.'); | 
 |   if (c != NULL) | 
 |     return c - name; | 
 |   else | 
 |     return strlen (name); | 
 | } | 
 |  | 
 | static void | 
 | compute_completer_bits (struct main_entry *ment, struct completer_entry *ent) | 
 | { | 
 |   while (ent != NULL) | 
 |     { | 
 |       compute_completer_bits (ment, ent->addl_entries); | 
 |  | 
 |       if (ent->is_terminal) | 
 | 	{ | 
 | 	  ia64_insn mask = 0; | 
 | 	  ia64_insn our_bits = ent->bits; | 
 | 	  struct completer_entry *p = ent->parent; | 
 | 	  ia64_insn p_bits; | 
 | 	  int x; | 
 |  | 
 | 	  while (p != NULL && ! p->is_terminal) | 
 | 	    p = p->parent; | 
 |  | 
 | 	  if (p != NULL) | 
 | 	    p_bits = p->bits; | 
 | 	  else | 
 | 	    p_bits = ment->opcode->opcode; | 
 |  | 
 | 	  for (x = 0; x < 64; x++) | 
 | 	    { | 
 | 	      ia64_insn m = ((ia64_insn) 1) << x; | 
 |  | 
 | 	      if ((p_bits & m) != (our_bits & m)) | 
 | 		mask |= m; | 
 | 	      else | 
 | 		our_bits &= ~m; | 
 | 	    } | 
 | 	  ent->bits = our_bits; | 
 | 	  ent->mask = mask; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  ent->bits = 0; | 
 | 	  ent->mask = 0; | 
 | 	} | 
 |  | 
 |       ent = ent->alternative; | 
 |     } | 
 | } | 
 |  | 
 | /* Find identical completer trees that are used in different | 
 |    instructions and collapse their entries.  */ | 
 | static void | 
 | collapse_redundant_completers (void) | 
 | { | 
 |   struct main_entry *ptr; | 
 |   int x; | 
 |  | 
 |   for (ptr = maintable; ptr != NULL; ptr = ptr->next) | 
 |     { | 
 |       if (ptr->completers == NULL) | 
 | 	abort (); | 
 |  | 
 |       compute_completer_bits (ptr, ptr->completers); | 
 |       ptr->completers = insert_gclist (ptr->completers); | 
 |     } | 
 |  | 
 |   /* The table has been finalized, now number the indexes.  */ | 
 |   for (x = 0; x < glistlen; x++) | 
 |     glist[x]->num = x; | 
 | } | 
 |  | 
 |  | 
 | /* Attach two lists of dependencies to each opcode. | 
 |    1) all resources which, when already marked in use, conflict with this | 
 |    opcode (chks) | 
 |    2) all resources which must be marked in use when this opcode is used | 
 |    (regs).  */ | 
 | static int | 
 | insert_opcode_dependencies (struct ia64_opcode *opc, | 
 |                             struct completer_entry *cmp ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Note all resources which point to this opcode.  rfi has the most chks | 
 |      (79) and cmpxchng has the most regs (54) so 100 here should be enough.  */ | 
 |   int i; | 
 |   int nregs = 0; | 
 |   unsigned short regs[256]; | 
 |   int nchks = 0; | 
 |   unsigned short chks[256]; | 
 |   /* Flag insns for which no class matched; there should be none.  */ | 
 |   int no_class_found = 1; | 
 |  | 
 |   for (i = 0; i < rdepslen; i++) | 
 |     { | 
 |       struct rdep *rs = rdeps[i]; | 
 |       int j; | 
 |  | 
 |       if (strcmp (opc->name, "cmp.eq.and") == 0 | 
 |           && startswith (rs->name, "PR%") | 
 |           && rs->mode == 1) | 
 |         no_class_found = 99; | 
 |  | 
 |       for (j=0; j < rs->nregs;j++) | 
 |         { | 
 |           int ic_note = 0; | 
 |  | 
 |           if (in_iclass (opc, ics[rs->regs[j]], NULL, NULL, &ic_note)) | 
 |             { | 
 |               /* We can ignore ic_note 11 for non PR resources.  */ | 
 |               if (ic_note == 11 && ! startswith (rs->name, "PR")) | 
 |                 ic_note = 0; | 
 |  | 
 |               if (ic_note != 0 && rs->regnotes[j] != 0 | 
 |                   && ic_note != rs->regnotes[j] | 
 |                   && !(ic_note == 11 && rs->regnotes[j] == 1)) | 
 |                 warn (_("IC note %d in opcode %s (IC:%s) conflicts with resource %s note %d\n"), | 
 | 		      ic_note, opc->name, ics[rs->regs[j]]->name, | 
 | 		      rs->name, rs->regnotes[j]); | 
 |               /* Instruction class notes override resource notes. | 
 |                  So far, only note 11 applies to an IC instead of a resource, | 
 |                  and note 11 implies note 1.  */ | 
 |               if (ic_note) | 
 |                 regs[nregs++] = RDEP(ic_note, i); | 
 |               else | 
 |                 regs[nregs++] = RDEP(rs->regnotes[j], i); | 
 |               no_class_found = 0; | 
 |               ++rs->total_regs; | 
 |             } | 
 |         } | 
 |  | 
 |       for (j = 0; j < rs->nchks; j++) | 
 |         { | 
 |           int ic_note = 0; | 
 |  | 
 |           if (in_iclass (opc, ics[rs->chks[j]], NULL, NULL, &ic_note)) | 
 |             { | 
 |               /* We can ignore ic_note 11 for non PR resources.  */ | 
 |               if (ic_note == 11 && ! startswith (rs->name, "PR")) | 
 |                 ic_note = 0; | 
 |  | 
 |               if (ic_note != 0 && rs->chknotes[j] != 0 | 
 |                   && ic_note != rs->chknotes[j] | 
 |                   && !(ic_note == 11 && rs->chknotes[j] == 1)) | 
 |                 warn (_("IC note %d for opcode %s (IC:%s) conflicts with resource %s note %d\n"), | 
 | 		      ic_note, opc->name, ics[rs->chks[j]]->name, | 
 | 		      rs->name, rs->chknotes[j]); | 
 |               if (ic_note) | 
 |                 chks[nchks++] = RDEP(ic_note, i); | 
 |               else | 
 |                 chks[nchks++] = RDEP(rs->chknotes[j], i); | 
 |               no_class_found = 0; | 
 |               ++rs->total_chks; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |   if (no_class_found) | 
 |     warn (_("opcode %s has no class (ops %d %d %d)\n"), | 
 | 	  opc->name, | 
 | 	  opc->operands[0], opc->operands[1], opc->operands[2]); | 
 |  | 
 |   return insert_dependencies (nchks, chks, nregs, regs); | 
 | } | 
 |  | 
 | static void | 
 | insert_completer_entry (struct ia64_opcode *opc, struct main_entry *tabent, | 
 |                         int order) | 
 | { | 
 |   struct completer_entry **ptr = &tabent->completers; | 
 |   struct completer_entry *parent = NULL; | 
 |   char pcopy[129], *prefix; | 
 |   int at_end = 0; | 
 |  | 
 |   if (strlen (opc->name) > 128) | 
 |     abort (); | 
 |  | 
 |   strcpy (pcopy, opc->name); | 
 |   prefix = pcopy + get_prefix_len (pcopy); | 
 |  | 
 |   if (prefix[0] != '\0') | 
 |     prefix++; | 
 |  | 
 |   while (! at_end) | 
 |     { | 
 |       int need_new_ent = 1; | 
 |       int plen = get_prefix_len (prefix); | 
 |       struct string_entry *sent; | 
 |  | 
 |       at_end = (prefix[plen] == '\0'); | 
 |       prefix[plen] = '\0'; | 
 |       sent = insert_string (prefix); | 
 |  | 
 |       while (*ptr != NULL) | 
 | 	{ | 
 | 	  int cmpres = sent->num - (*ptr)->name->num; | 
 |  | 
 | 	  if (cmpres == 0) | 
 | 	    { | 
 | 	      need_new_ent = 0; | 
 | 	      break; | 
 | 	    } | 
 | 	  else | 
 | 	    ptr = &((*ptr)->alternative); | 
 | 	} | 
 |  | 
 |       if (need_new_ent) | 
 | 	{ | 
 | 	  struct completer_entry *nent = tmalloc (struct completer_entry); | 
 |  | 
 | 	  nent->name = sent; | 
 | 	  nent->parent = parent; | 
 | 	  nent->addl_entries = NULL; | 
 | 	  nent->alternative = *ptr; | 
 | 	  *ptr = nent; | 
 | 	  nent->is_terminal = 0; | 
 |           nent->dependencies = -1; | 
 | 	} | 
 |  | 
 |       if (! at_end) | 
 | 	{ | 
 | 	  parent = *ptr; | 
 | 	  ptr = &((*ptr)->addl_entries); | 
 | 	  prefix += plen + 1; | 
 | 	} | 
 |     } | 
 |  | 
 |   if ((*ptr)->is_terminal) | 
 |     abort (); | 
 |  | 
 |   (*ptr)->is_terminal = 1; | 
 |   (*ptr)->mask = (ia64_insn)-1; | 
 |   (*ptr)->bits = opc->opcode; | 
 |   (*ptr)->dependencies = insert_opcode_dependencies (opc, *ptr); | 
 |   (*ptr)->order = order; | 
 | } | 
 |  | 
 | static void | 
 | print_completer_entry (struct completer_entry *ent) | 
 | { | 
 |   int moffset = 0; | 
 |   ia64_insn mask = ent->mask, bits = ent->bits; | 
 |  | 
 |   if (mask != 0) | 
 |     { | 
 |       while (! (mask & 1)) | 
 | 	{ | 
 | 	  moffset++; | 
 | 	  mask = mask >> 1; | 
 | 	  bits = bits >> 1; | 
 | 	} | 
 |  | 
 |       if (bits & 0xffffffff00000000LL) | 
 | 	abort (); | 
 |     } | 
 |  | 
 |   printf ("  { 0x%x, 0x%x, %d, %d, %d, %d, %d, %d },\n", | 
 | 	  (int)bits, | 
 | 	  (int)mask, | 
 | 	  ent->name->num, | 
 | 	  ent->alternative != NULL ? ent->alternative->num : -1, | 
 | 	  ent->addl_entries != NULL ? ent->addl_entries->num : -1, | 
 | 	  moffset, | 
 | 	  ent->is_terminal ? 1 : 0, | 
 |           ent->dependencies); | 
 | } | 
 |  | 
 | static void | 
 | print_completer_table (void) | 
 | { | 
 |   int x; | 
 |  | 
 |   printf ("static const struct ia64_completer_table\ncompleter_table[] = {\n"); | 
 |   for (x = 0; x < glistlen; x++) | 
 |     print_completer_entry (glist[x]); | 
 |   printf ("};\n\n"); | 
 | } | 
 |  | 
 | static int | 
 | opcodes_eq (struct ia64_opcode *opc1, struct ia64_opcode *opc2) | 
 | { | 
 |   int x; | 
 |   int plen1, plen2; | 
 |  | 
 |   if ((opc1->mask != opc2->mask) || (opc1->type != opc2->type) | 
 |       || (opc1->num_outputs != opc2->num_outputs) | 
 |       || (opc1->flags != opc2->flags)) | 
 |     return 0; | 
 |  | 
 |   for (x = 0; x < 5; x++) | 
 |     if (opc1->operands[x] != opc2->operands[x]) | 
 |       return 0; | 
 |  | 
 |   plen1 = get_prefix_len (opc1->name); | 
 |   plen2 = get_prefix_len (opc2->name); | 
 |  | 
 |   if (plen1 == plen2 && (memcmp (opc1->name, opc2->name, plen1) == 0)) | 
 |     return 1; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | static void | 
 | add_opcode_entry (struct ia64_opcode *opc) | 
 | { | 
 |   struct main_entry **place; | 
 |   struct string_entry *name; | 
 |   char prefix[129]; | 
 |   int found_it = 0; | 
 |  | 
 |   if (strlen (opc->name) > 128) | 
 |     abort (); | 
 |  | 
 |   place = &maintable; | 
 |   strcpy (prefix, opc->name); | 
 |   prefix[get_prefix_len (prefix)] = '\0'; | 
 |   name = insert_string (prefix); | 
 |  | 
 |   /* Walk the list of opcode table entries.  If it's a new | 
 |      instruction, allocate and fill in a new entry.  Note | 
 |      the main table is alphabetical by opcode name.  */ | 
 |  | 
 |   while (*place != NULL) | 
 |     { | 
 |       if ((*place)->name->num == name->num | 
 | 	  && opcodes_eq ((*place)->opcode, opc)) | 
 | 	{ | 
 | 	  found_it = 1; | 
 | 	  break; | 
 | 	} | 
 |       if ((*place)->name->num > name->num) | 
 | 	break; | 
 |  | 
 |       place = &((*place)->next); | 
 |     } | 
 |   if (! found_it) | 
 |     { | 
 |       struct main_entry *nent = tmalloc (struct main_entry); | 
 |  | 
 |       nent->name = name; | 
 |       nent->opcode = opc; | 
 |       nent->next = *place; | 
 |       nent->completers = 0; | 
 |       *place = nent; | 
 |  | 
 |       if (otlen == ottotlen) | 
 |         { | 
 |           ottotlen += 20; | 
 |           ordered_table = (struct main_entry **) | 
 |             xrealloc (ordered_table, sizeof (struct main_entry *) * ottotlen); | 
 |         } | 
 |       ordered_table[otlen++] = nent; | 
 |     } | 
 |  | 
 |   insert_completer_entry (opc, *place, opcode_count++); | 
 | } | 
 |  | 
 | static void | 
 | print_main_table (void) | 
 | { | 
 |   struct main_entry *ptr = maintable; | 
 |   int tindex = 0; | 
 |  | 
 |   printf ("static const struct ia64_main_table\nmain_table[] = {\n"); | 
 |   while (ptr != NULL) | 
 |     { | 
 |       printf ("  { %d, %d, %d, 0x%016" PRIx64 "ull, 0x%016" PRIx64 | 
 | 	      "ull, { %d, %d, %d, %d, %d }, 0x%x, %d, },\n", | 
 | 	      ptr->name->num, | 
 | 	      ptr->opcode->type, | 
 | 	      ptr->opcode->num_outputs, | 
 | 	      ptr->opcode->opcode, | 
 | 	      ptr->opcode->mask, | 
 | 	      ptr->opcode->operands[0], | 
 | 	      ptr->opcode->operands[1], | 
 | 	      ptr->opcode->operands[2], | 
 | 	      ptr->opcode->operands[3], | 
 | 	      ptr->opcode->operands[4], | 
 | 	      ptr->opcode->flags, | 
 | 	      ptr->completers->num); | 
 |  | 
 |       ptr->main_index = tindex++; | 
 |  | 
 |       ptr = ptr->next; | 
 |     } | 
 |   printf ("};\n\n"); | 
 | } | 
 |  | 
 | static void | 
 | shrink (struct ia64_opcode *table) | 
 | { | 
 |   int curr_opcode; | 
 |  | 
 |   for (curr_opcode = 0; table[curr_opcode].name != NULL; curr_opcode++) | 
 |     { | 
 |       add_opcode_entry (table + curr_opcode); | 
 |       if (table[curr_opcode].num_outputs == 2 | 
 | 	  && ((table[curr_opcode].operands[0] == IA64_OPND_P1 | 
 | 	       && table[curr_opcode].operands[1] == IA64_OPND_P2) | 
 | 	      || (table[curr_opcode].operands[0] == IA64_OPND_P2 | 
 | 		  && table[curr_opcode].operands[1] == IA64_OPND_P1))) | 
 | 	{ | 
 | 	  struct ia64_opcode *alias = tmalloc(struct ia64_opcode); | 
 | 	  unsigned i; | 
 |  | 
 | 	  *alias = table[curr_opcode]; | 
 | 	  for (i = 2; i < NELEMS (alias->operands); ++i) | 
 | 	    alias->operands[i - 1] = alias->operands[i]; | 
 | 	  alias->operands[NELEMS (alias->operands) - 1] = IA64_OPND_NIL; | 
 | 	  --alias->num_outputs; | 
 | 	  alias->flags |= PSEUDO; | 
 | 	  add_opcode_entry (alias); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Program options.  */ | 
 | #define OPTION_SRCDIR	200 | 
 |  | 
 | struct option long_options[] = | 
 | { | 
 |   {"srcdir",  required_argument, NULL, OPTION_SRCDIR}, | 
 |   {"debug",   no_argument,       NULL, 'd'}, | 
 |   {"version", no_argument,       NULL, 'V'}, | 
 |   {"help",    no_argument,       NULL, 'h'}, | 
 |   {0,         no_argument,       NULL, 0} | 
 | }; | 
 |  | 
 | static void | 
 | print_version (void) | 
 | { | 
 |   printf ("%s: version 1.0\n", program_name); | 
 |   xexit (0); | 
 | } | 
 |  | 
 | static void | 
 | usage (FILE * stream, int status) | 
 | { | 
 |   fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n", | 
 | 	   program_name); | 
 |   xexit (status); | 
 | } | 
 |  | 
 | int | 
 | main (int argc, char **argv) | 
 | { | 
 |   extern int chdir (char *); | 
 |   char *srcdir = NULL; | 
 |   int c; | 
 |  | 
 |   program_name = *argv; | 
 |   xmalloc_set_program_name (program_name); | 
 |  | 
 |   while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF) | 
 |     switch (c) | 
 |       { | 
 |       case OPTION_SRCDIR: | 
 | 	srcdir = optarg; | 
 | 	break; | 
 |       case 'V': | 
 |       case 'v': | 
 | 	print_version (); | 
 | 	break; | 
 |       case 'd': | 
 | 	debug = 1; | 
 | 	break; | 
 |       case 'h': | 
 |       case '?': | 
 | 	usage (stderr, 0); | 
 |       default: | 
 |       case 0: | 
 | 	break; | 
 |       } | 
 |  | 
 |   if (optind != argc) | 
 |     usage (stdout, 1); | 
 |  | 
 |   if (srcdir != NULL) | 
 |     if (chdir (srcdir) != 0) | 
 |       fail (_("unable to change directory to \"%s\", errno = %s\n"), | 
 | 	    srcdir, strerror (errno)); | 
 |  | 
 |   load_insn_classes (); | 
 |   load_dependencies (); | 
 |  | 
 |   shrink (ia64_opcodes_a); | 
 |   shrink (ia64_opcodes_b); | 
 |   shrink (ia64_opcodes_f); | 
 |   shrink (ia64_opcodes_i); | 
 |   shrink (ia64_opcodes_m); | 
 |   shrink (ia64_opcodes_x); | 
 |   shrink (ia64_opcodes_d); | 
 |  | 
 |   collapse_redundant_completers (); | 
 |  | 
 |   printf ("/* This file is automatically generated by ia64-gen.  Do not edit!  */\n"); | 
 |   printf ("/* Copyright (C) 2007-2024 Free Software Foundation, Inc.\n\ | 
 | \n\ | 
 |    This file is part of the GNU opcodes library.\n\ | 
 | \n\ | 
 |    This library is free software; you can redistribute it and/or modify\n\ | 
 |    it under the terms of the GNU General Public License as published by\n\ | 
 |    the Free Software Foundation; either version 3, or (at your option)\n\ | 
 |    any later version.\n\ | 
 | \n\ | 
 |    It is distributed in the hope that it will be useful, but WITHOUT\n\ | 
 |    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\ | 
 |    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public\n\ | 
 |    License for more details.\n\ | 
 | \n\ | 
 |    You should have received a copy of the GNU General Public License\n\ | 
 |    along with this program; see the file COPYING.  If not, write to the\n\ | 
 |    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA\n\ | 
 |    02110-1301, USA.  */\n"); | 
 |  | 
 |   print_string_table (); | 
 |   print_dependency_table (); | 
 |   print_completer_table (); | 
 |   print_main_table (); | 
 |  | 
 |   generate_disassembler (); | 
 |  | 
 |   exit (0); | 
 | } |