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