ia64-opc.c revision 89857
184865Sobrien/* ia64-opc.c -- Functions to access the compacted opcode table
284865Sobrien   Copyright 1999, 2000 Free Software Foundation, Inc.
384865Sobrien   Written by Bob Manson of Cygnus Solutions, <manson@cygnus.com>
484865Sobrien
584865Sobrien   This file is part of GDB, GAS, and the GNU binutils.
684865Sobrien
784865Sobrien   GDB, GAS, and the GNU binutils are free software; you can redistribute
884865Sobrien   them and/or modify them under the terms of the GNU General Public
984865Sobrien   License as published by the Free Software Foundation; either version
1084865Sobrien   2, or (at your option) any later version.
1184865Sobrien
1284865Sobrien   GDB, GAS, and the GNU binutils are distributed in the hope that they
1384865Sobrien   will be useful, but WITHOUT ANY WARRANTY; without even the implied
1484865Sobrien   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1584865Sobrien   the GNU General Public License for more details.
1684865Sobrien
1784865Sobrien   You should have received a copy of the GNU General Public License
1884865Sobrien   along with this file; see the file COPYING.  If not, write to the
1984865Sobrien   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2084865Sobrien   02111-1307, USA.  */
2184865Sobrien
2284865Sobrien#include "ansidecl.h"
2384865Sobrien#include "libiberty.h"
2484865Sobrien#include "sysdep.h"
2584865Sobrien#include "ia64-asmtab.h"
2684865Sobrien#include "ia64-asmtab.c"
2784865Sobrien
2889857Sobrienstatic void get_opc_prefix PARAMS ((const char **, char *));
2989857Sobrienstatic short int find_string_ent PARAMS ((const char *));
3089857Sobrienstatic short int find_main_ent PARAMS ((short int));
3189857Sobrienstatic short int find_completer PARAMS ((short int, short int, const char *));
3289857Sobrienstatic ia64_insn apply_completer PARAMS ((ia64_insn, int));
3389857Sobrienstatic int extract_op_bits PARAMS ((int, int, int));
3489857Sobrienstatic int extract_op PARAMS ((int, int *, unsigned int *));
3589857Sobrienstatic int opcode_verify PARAMS ((ia64_insn, int, enum ia64_insn_type));
3689857Sobrienstatic int locate_opcode_ent PARAMS ((ia64_insn, enum ia64_insn_type));
3789857Sobrienstatic struct ia64_opcode *make_ia64_opcode
3889857Sobrien  PARAMS ((ia64_insn, const char *, int, int));
3989857Sobrienstatic struct ia64_opcode *ia64_find_matching_opcode
4089857Sobrien  PARAMS ((const char *, short int));
4189857Sobrien
4284865Sobrienconst struct ia64_templ_desc ia64_templ_desc[16] =
4384865Sobrien  {
4484865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },	/* 0 */
4584865Sobrien    { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },
4684865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" },
4784865Sobrien    { 0, { 0, },				    "-3-" },
4884865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },	/* 4 */
4984865Sobrien    { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },
5084865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" },
5184865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" },
5284865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" },	/* 8 */
5384865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" },
5484865Sobrien    { 0, { 0, },				    "-a-" },
5584865Sobrien    { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" },
5684865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" },	/* c */
5784865Sobrien    { 0, { 0, },				    "-d-" },
5884865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" },
5984865Sobrien    { 0, { 0, },				    "-f-" },
6084865Sobrien  };
6184865Sobrien
6284865Sobrien
6384865Sobrien/* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST.
6484865Sobrien   PTR will be adjusted to point to the start of the next portion
6584865Sobrien   of the opcode, or at the NUL character. */
6684865Sobrien
6784865Sobrienstatic void
6884865Sobrienget_opc_prefix (ptr, dest)
6984865Sobrien     const char **ptr;
7084865Sobrien     char *dest;
7184865Sobrien{
7284865Sobrien  char *c = strchr (*ptr, '.');
7384865Sobrien  if (c != NULL)
7484865Sobrien    {
7584865Sobrien      memcpy (dest, *ptr, c - *ptr);
7684865Sobrien      dest[c - *ptr] = '\0';
7784865Sobrien      *ptr = c + 1;
7884865Sobrien    }
7984865Sobrien  else
8084865Sobrien    {
8184865Sobrien      int l = strlen (*ptr);
8284865Sobrien      memcpy (dest, *ptr, l);
8384865Sobrien      dest[l] = '\0';
8484865Sobrien      *ptr += l;
8584865Sobrien    }
8684865Sobrien}
8784865Sobrien
8884865Sobrien/* Find the index of the entry in the string table corresponding to
8984865Sobrien   STR; return -1 if one does not exist. */
9084865Sobrien
9184865Sobrienstatic short
9284865Sobrienfind_string_ent (str)
9384865Sobrien     const char *str;
9484865Sobrien{
9584865Sobrien  short start = 0;
9684865Sobrien  short end = sizeof (ia64_strings) / sizeof (const char *);
9784865Sobrien  short i = (start + end) / 2;
9884865Sobrien
9984865Sobrien  if (strcmp (str, ia64_strings[end - 1]) > 0)
10084865Sobrien    {
10184865Sobrien      return -1;
10284865Sobrien    }
10384865Sobrien  while (start <= end)
10484865Sobrien    {
10584865Sobrien      int c = strcmp (str, ia64_strings[i]);
10684865Sobrien      if (c < 0)
10784865Sobrien	{
10884865Sobrien	  end = i - 1;
10984865Sobrien	}
11084865Sobrien      else if (c == 0)
11184865Sobrien	{
11284865Sobrien	  return i;
11384865Sobrien	}
11484865Sobrien      else
11584865Sobrien	{
11684865Sobrien	  start = i + 1;
11784865Sobrien	}
11884865Sobrien      i = (start + end) / 2;
11984865Sobrien    }
12084865Sobrien  return -1;
12184865Sobrien}
12284865Sobrien
12384865Sobrien/* Find the opcode in the main opcode table whose name is STRINGINDEX, or
12484865Sobrien   return -1 if one does not exist. */
12584865Sobrien
12684865Sobrienstatic short
12784865Sobrienfind_main_ent (nameindex)
12884865Sobrien     short nameindex;
12984865Sobrien{
13084865Sobrien  short start = 0;
13184865Sobrien  short end = sizeof (main_table) / sizeof (struct ia64_main_table);
13284865Sobrien  short i = (start + end) / 2;
13384865Sobrien
13484865Sobrien  if (nameindex < main_table[0].name_index
13584865Sobrien      || nameindex > main_table[end - 1].name_index)
13684865Sobrien    {
13784865Sobrien      return -1;
13884865Sobrien    }
13984865Sobrien  while (start <= end)
14084865Sobrien    {
14184865Sobrien      if (nameindex < main_table[i].name_index)
14284865Sobrien	{
14384865Sobrien	  end = i - 1;
14484865Sobrien	}
14584865Sobrien      else if (nameindex == main_table[i].name_index)
14684865Sobrien	{
14784865Sobrien	  while (i > 0 && main_table[i - 1].name_index == nameindex)
14884865Sobrien	    {
14984865Sobrien	      i--;
15084865Sobrien	    }
15184865Sobrien	  return i;
15284865Sobrien	}
15384865Sobrien      else
15484865Sobrien	{
15584865Sobrien	  start = i + 1;
15684865Sobrien	}
15784865Sobrien      i = (start + end) / 2;
15884865Sobrien    }
15984865Sobrien  return -1;
16084865Sobrien}
16184865Sobrien
16284865Sobrien/* Find the index of the entry in the completer table that is part of
16384865Sobrien   MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or
16484865Sobrien   return -1 if one does not exist. */
16584865Sobrien
16689857Sobrienstatic short
16784865Sobrienfind_completer (main_ent, prev_completer, name)
16884865Sobrien     short main_ent;
16984865Sobrien     short prev_completer;
17084865Sobrien     const char *name;
17184865Sobrien{
17284865Sobrien  short name_index = find_string_ent (name);
17384865Sobrien
17484865Sobrien  if (name_index < 0)
17584865Sobrien    {
17684865Sobrien      return -1;
17784865Sobrien    }
17884865Sobrien
17984865Sobrien  if (prev_completer == -1)
18084865Sobrien    {
18184865Sobrien      prev_completer = main_table[main_ent].completers;
18284865Sobrien    }
18384865Sobrien  else
18484865Sobrien    {
18584865Sobrien      prev_completer = completer_table[prev_completer].subentries;
18684865Sobrien    }
18784865Sobrien
18884865Sobrien  while (prev_completer != -1)
18984865Sobrien    {
19084865Sobrien      if (completer_table[prev_completer].name_index == name_index)
19184865Sobrien	{
19284865Sobrien	  return prev_completer;
19384865Sobrien	}
19484865Sobrien      prev_completer = completer_table[prev_completer].alternative;
19584865Sobrien    }
19684865Sobrien  return -1;
19784865Sobrien}
19884865Sobrien
19984865Sobrien/* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and
20084865Sobrien   return the result. */
20184865Sobrien
20284865Sobrienstatic ia64_insn
20384865Sobrienapply_completer (opcode, completer_index)
20484865Sobrien     ia64_insn opcode;
20584865Sobrien     int completer_index;
20684865Sobrien{
20784865Sobrien  ia64_insn mask = completer_table[completer_index].mask;
20884865Sobrien  ia64_insn bits = completer_table[completer_index].bits;
20984865Sobrien  int shiftamt = (completer_table[completer_index].offset & 63);
21084865Sobrien
21184865Sobrien  mask = mask << shiftamt;
21284865Sobrien  bits = bits << shiftamt;
21384865Sobrien  opcode = (opcode & ~mask) | bits;
21484865Sobrien  return opcode;
21584865Sobrien}
21684865Sobrien
21784865Sobrien/* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in
21884865Sobrien   the dis_table array, and return its value.  (BITOFFSET is numbered
21984865Sobrien   starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the
22084865Sobrien   first byte in OP_POINTER.) */
22184865Sobrien
22284865Sobrienstatic int
22384865Sobrienextract_op_bits (op_pointer, bitoffset, bits)
22484865Sobrien     int op_pointer;
22584865Sobrien     int bitoffset;
22684865Sobrien     int bits;
22784865Sobrien{
22884865Sobrien  int res = 0;
22984865Sobrien
23084865Sobrien  op_pointer += (bitoffset / 8);
23184865Sobrien
23284865Sobrien  if (bitoffset % 8)
23384865Sobrien    {
23484865Sobrien      unsigned int op = dis_table[op_pointer++];
23584865Sobrien      int numb = 8 - (bitoffset % 8);
23684865Sobrien      int mask = (1 << numb) - 1;
23784865Sobrien      int bata = (bits < numb) ? bits : numb;
23884865Sobrien      int delta = numb - bata;
23984865Sobrien
24084865Sobrien      res = (res << bata) | ((op & mask) >> delta);
24184865Sobrien      bitoffset += bata;
24284865Sobrien      bits -= bata;
24384865Sobrien    }
24484865Sobrien  while (bits >= 8)
24584865Sobrien    {
24684865Sobrien      res = (res << 8) | (dis_table[op_pointer++] & 255);
24784865Sobrien      bits -= 8;
24884865Sobrien    }
24984865Sobrien  if (bits > 0)
25084865Sobrien    {
25184865Sobrien      unsigned int op = (dis_table[op_pointer++] & 255);
25284865Sobrien      res = (res << bits) | (op >> (8 - bits));
25384865Sobrien    }
25484865Sobrien  return res;
25584865Sobrien}
25684865Sobrien
25784865Sobrien/* Examine the state machine entry at OP_POINTER in the dis_table
25884865Sobrien   array, and extract its values into OPVAL and OP.  The length of the
25984865Sobrien   state entry in bits is returned. */
26084865Sobrien
26184865Sobrienstatic int
26284865Sobrienextract_op (op_pointer, opval, op)
26384865Sobrien     int op_pointer;
26484865Sobrien     int *opval;
26584865Sobrien     unsigned int *op;
26684865Sobrien{
26784865Sobrien  int oplen = 5;
26884865Sobrien
26984865Sobrien  *op = dis_table[op_pointer];
27084865Sobrien
27184865Sobrien  if ((*op) & 0x40)
27284865Sobrien    {
27384865Sobrien      opval[0] = extract_op_bits (op_pointer, oplen, 5);
27484865Sobrien      oplen += 5;
27584865Sobrien    }
27684865Sobrien  switch ((*op) & 0x30)
27784865Sobrien    {
27884865Sobrien    case 0x10:
27984865Sobrien      {
28084865Sobrien	opval[1] = extract_op_bits (op_pointer, oplen, 8);
28184865Sobrien	oplen += 8;
28284865Sobrien	opval[1] += op_pointer;
28384865Sobrien	break;
28484865Sobrien      }
28584865Sobrien    case 0x20:
28684865Sobrien      {
28784865Sobrien	opval[1] = extract_op_bits (op_pointer, oplen, 16);
28884865Sobrien	if (! (opval[1] & 32768))
28984865Sobrien	  {
29084865Sobrien	    opval[1] += op_pointer;
29184865Sobrien	  }
29284865Sobrien	oplen += 16;
29384865Sobrien	break;
29484865Sobrien      }
29584865Sobrien    case 0x30:
29684865Sobrien      {
29784865Sobrien	oplen--;
29884865Sobrien	opval[2] = extract_op_bits (op_pointer, oplen, 12);
29984865Sobrien	oplen += 12;
30084865Sobrien	opval[2] |= 32768;
30184865Sobrien	break;
30284865Sobrien      }
30384865Sobrien    }
30484865Sobrien  if (((*op) & 0x08) && (((*op) & 0x30) != 0x30))
30584865Sobrien    {
30684865Sobrien      opval[2] = extract_op_bits (op_pointer, oplen, 16);
30784865Sobrien      oplen += 16;
30884865Sobrien      if (! (opval[2] & 32768))
30984865Sobrien	{
31084865Sobrien	  opval[2] += op_pointer;
31184865Sobrien	}
31284865Sobrien    }
31384865Sobrien  return oplen;
31484865Sobrien}
31584865Sobrien
31684865Sobrien/* Returns a non-zero value if the opcode in the main_table list at
31784865Sobrien   PLACE matches OPCODE and is of type TYPE. */
31884865Sobrien
31984865Sobrienstatic int
32084865Sobrienopcode_verify (opcode, place, type)
32184865Sobrien     ia64_insn opcode;
32284865Sobrien     int place;
32384865Sobrien     enum ia64_insn_type type;
32484865Sobrien{
32584865Sobrien  if (main_table[place].opcode_type != type)
32684865Sobrien    {
32784865Sobrien      return 0;
32884865Sobrien    }
32989857Sobrien  if (main_table[place].flags
33084865Sobrien      & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT))
33184865Sobrien    {
33284865Sobrien      const struct ia64_operand *o1, *o2;
33384865Sobrien      ia64_insn f2, f3;
33484865Sobrien
33584865Sobrien      if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3)
33684865Sobrien	{
33784865Sobrien	  o1 = elf64_ia64_operands + IA64_OPND_F2;
33884865Sobrien	  o2 = elf64_ia64_operands + IA64_OPND_F3;
33984865Sobrien	  (*o1->extract) (o1, opcode, &f2);
34084865Sobrien	  (*o2->extract) (o2, opcode, &f3);
34184865Sobrien	  if (f2 != f3)
34284865Sobrien	    return 0;
34384865Sobrien	}
34484865Sobrien      else
34584865Sobrien	{
34684865Sobrien	  ia64_insn len, count;
34784865Sobrien
34884865Sobrien	  /* length must equal 64-count: */
34984865Sobrien	  o1 = elf64_ia64_operands + IA64_OPND_LEN6;
35084865Sobrien	  o2 = elf64_ia64_operands + main_table[place].operands[2];
35184865Sobrien	  (*o1->extract) (o1, opcode, &len);
35284865Sobrien	  (*o2->extract) (o2, opcode, &count);
35384865Sobrien	  if (len != 64 - count)
35484865Sobrien	    return 0;
35584865Sobrien	}
35684865Sobrien    }
35784865Sobrien  return 1;
35884865Sobrien}
35984865Sobrien
36084865Sobrien/* Find an instruction entry in the ia64_dis_names array that matches
36184865Sobrien   opcode OPCODE and is of type TYPE.  Returns either a positive index
36284865Sobrien   into the array, or a negative value if an entry for OPCODE could
36384865Sobrien   not be found.  Checks all matches and returns the one with the highest
36484865Sobrien   priority. */
36584865Sobrien
36684865Sobrienstatic int
36784865Sobrienlocate_opcode_ent (opcode, type)
36884865Sobrien     ia64_insn opcode;
36984865Sobrien     enum ia64_insn_type type;
37084865Sobrien{
37184865Sobrien  int currtest[41];
37284865Sobrien  int bitpos[41];
37384865Sobrien  int op_ptr[41];
37484865Sobrien  int currstatenum = 0;
37584865Sobrien  short found_disent = -1;
37684865Sobrien  short found_priority = -1;
37784865Sobrien
37884865Sobrien  currtest[currstatenum] = 0;
37984865Sobrien  op_ptr[currstatenum] = 0;
38084865Sobrien  bitpos[currstatenum] = 40;
38184865Sobrien
38284865Sobrien  while (1)
38384865Sobrien    {
38484865Sobrien      int op_pointer = op_ptr[currstatenum];
38584865Sobrien      unsigned int op;
38684865Sobrien      int currbitnum = bitpos[currstatenum];
38784865Sobrien      int oplen;
38884865Sobrien      int opval[3];
38984865Sobrien      int next_op;
39084865Sobrien      int currbit;
39184865Sobrien
39284865Sobrien      oplen = extract_op (op_pointer, opval, &op);
39384865Sobrien
39484865Sobrien      bitpos[currstatenum] = currbitnum;
39584865Sobrien
39684865Sobrien      /* Skip opval[0] bits in the instruction. */
39784865Sobrien      if (op & 0x40)
39884865Sobrien	{
39984865Sobrien	  currbitnum -= opval[0];
40084865Sobrien	}
40184865Sobrien
40284865Sobrien      /* The value of the current bit being tested. */
40384865Sobrien      currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0;
40484865Sobrien      next_op = -1;
40584865Sobrien
40684865Sobrien      /* We always perform the tests specified in the current state in
40784865Sobrien	 a particular order, falling through to the next test if the
40884865Sobrien	 previous one failed. */
40984865Sobrien      switch (currtest[currstatenum])
41084865Sobrien	{
41184865Sobrien	case 0:
41284865Sobrien	  currtest[currstatenum]++;
41384865Sobrien	  if (currbit == 0 && (op & 0x80))
41484865Sobrien	    {
41584865Sobrien	      /* Check for a zero bit.  If this test solely checks for
41684865Sobrien		 a zero bit, we can check for up to 8 consecutive zero
41784865Sobrien		 bits (the number to check is specified by the lower 3
41884865Sobrien		 bits in the state code.)
41984865Sobrien
42084865Sobrien		 If the state instruction matches, we go to the very
42184865Sobrien		 next state instruction; otherwise, try the next test. */
42284865Sobrien
42384865Sobrien	      if ((op & 0xf8) == 0x80)
42484865Sobrien		{
42584865Sobrien		  int count = op & 0x7;
42684865Sobrien		  int x;
42784865Sobrien
42884865Sobrien		  for (x = 0; x <= count; x++)
42984865Sobrien		    {
43084865Sobrien		      int i =
43184865Sobrien			opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0;
43284865Sobrien		      if (i)
43384865Sobrien			{
43484865Sobrien			  break;
43584865Sobrien			}
43684865Sobrien		    }
43784865Sobrien		  if (x > count)
43884865Sobrien		    {
43984865Sobrien		      next_op = op_pointer + ((oplen + 7) / 8);
44084865Sobrien		      currbitnum -= count;
44184865Sobrien		      break;
44284865Sobrien		    }
44384865Sobrien		}
44484865Sobrien	      else if (! currbit)
44584865Sobrien		{
44684865Sobrien		  next_op = op_pointer + ((oplen + 7) / 8);
44784865Sobrien		  break;
44884865Sobrien		}
44984865Sobrien	    }
45084865Sobrien	  /* FALLTHROUGH */
45184865Sobrien	case 1:
45284865Sobrien	  /* If the bit in the instruction is one, go to the state
45384865Sobrien	     instruction specified by opval[1]. */
45484865Sobrien	  currtest[currstatenum]++;
45584865Sobrien	  if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30))
45684865Sobrien	    {
45784865Sobrien	      next_op = opval[1];
45884865Sobrien	      break;
45984865Sobrien	    }
46084865Sobrien	  /* FALLTHROUGH */
46184865Sobrien	case 2:
46284865Sobrien	  /* Don't care.  Skip the current bit and go to the state
46384865Sobrien	     instruction specified by opval[2].
46484865Sobrien
46584865Sobrien	     An encoding of 0x30 is special; this means that a 12-bit
46684865Sobrien	     offset into the ia64_dis_names[] array is specified.  */
46784865Sobrien	  currtest[currstatenum]++;
46884865Sobrien	  if ((op & 0x08) || ((op & 0x30) == 0x30))
46984865Sobrien	    {
47084865Sobrien	      next_op = opval[2];
47184865Sobrien	      break;
47284865Sobrien	    }
47384865Sobrien	}
47484865Sobrien
47584865Sobrien      /* If bit 15 is set in the address of the next state, an offset
47684865Sobrien	 in the ia64_dis_names array was specified instead.  We then
47784865Sobrien	 check to see if an entry in the list of opcodes matches the
47884865Sobrien	 opcode we were given; if so, we have succeeded.  */
47984865Sobrien
48084865Sobrien      if ((next_op >= 0) && (next_op & 32768))
48184865Sobrien	{
48284865Sobrien	  short disent = next_op & 32767;
48384865Sobrien          short priority = -1;
48484865Sobrien
48584865Sobrien	  if (next_op > 65535)
48684865Sobrien	    {
48784865Sobrien	      abort ();
48884865Sobrien	    }
48984865Sobrien
49084865Sobrien	  /* Run through the list of opcodes to check, trying to find
49184865Sobrien	     one that matches.  */
49284865Sobrien	  while (disent >= 0)
49384865Sobrien	    {
49484865Sobrien	      int place = ia64_dis_names[disent].insn_index;
49584865Sobrien
49684865Sobrien              priority = ia64_dis_names[disent].priority;
49784865Sobrien
49889857Sobrien	      if (opcode_verify (opcode, place, type)
49984865Sobrien                  && priority > found_priority)
50084865Sobrien		{
50184865Sobrien		  break;
50284865Sobrien		}
50384865Sobrien	      if (ia64_dis_names[disent].next_flag)
50484865Sobrien		{
50584865Sobrien		  disent++;
50684865Sobrien		}
50784865Sobrien	      else
50884865Sobrien		{
50984865Sobrien		  disent = -1;
51084865Sobrien		}
51184865Sobrien	    }
51284865Sobrien
51384865Sobrien	  if (disent >= 0)
51484865Sobrien	    {
51584865Sobrien              found_disent = disent;
51684865Sobrien              found_priority = priority;
51784865Sobrien	    }
51884865Sobrien          /* Try the next test in this state, regardless of whether a match
51984865Sobrien             was found. */
52084865Sobrien          next_op = -2;
52184865Sobrien	}
52284865Sobrien
52384865Sobrien      /* next_op == -1 is "back up to the previous state".
52484865Sobrien	 next_op == -2 is "stay in this state and try the next test".
52584865Sobrien	 Otherwise, transition to the state indicated by next_op. */
52684865Sobrien
52784865Sobrien      if (next_op == -1)
52884865Sobrien	{
52984865Sobrien	  currstatenum--;
53084865Sobrien	  if (currstatenum < 0)
53184865Sobrien	    {
53284865Sobrien              return found_disent;
53384865Sobrien	    }
53484865Sobrien	}
53584865Sobrien      else if (next_op >= 0)
53684865Sobrien	{
53784865Sobrien	  currstatenum++;
53884865Sobrien	  bitpos[currstatenum] = currbitnum - 1;
53984865Sobrien	  op_ptr[currstatenum] = next_op;
54084865Sobrien	  currtest[currstatenum] = 0;
54184865Sobrien	}
54284865Sobrien    }
54384865Sobrien}
54484865Sobrien
54584865Sobrien/* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */
54684865Sobrien
54784865Sobrienstatic struct ia64_opcode *
54884865Sobrienmake_ia64_opcode (opcode, name, place, depind)
54984865Sobrien     ia64_insn opcode;
55084865Sobrien     const char *name;
55184865Sobrien     int place;
55284865Sobrien     int depind;
55384865Sobrien{
55484865Sobrien  struct ia64_opcode *res =
55584865Sobrien    (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode));
55684865Sobrien  res->name = xstrdup (name);
55784865Sobrien  res->type = main_table[place].opcode_type;
55884865Sobrien  res->num_outputs = main_table[place].num_outputs;
55984865Sobrien  res->opcode = opcode;
56084865Sobrien  res->mask = main_table[place].mask;
56184865Sobrien  res->operands[0] = main_table[place].operands[0];
56284865Sobrien  res->operands[1] = main_table[place].operands[1];
56384865Sobrien  res->operands[2] = main_table[place].operands[2];
56484865Sobrien  res->operands[3] = main_table[place].operands[3];
56584865Sobrien  res->operands[4] = main_table[place].operands[4];
56684865Sobrien  res->flags = main_table[place].flags;
56784865Sobrien  res->ent_index = place;
56884865Sobrien  res->dependencies = &op_dependencies[depind];
56984865Sobrien  return res;
57084865Sobrien}
57184865Sobrien
57284865Sobrien/* Determine the ia64_opcode entry for the opcode specified by INSN
57384865Sobrien   and TYPE.  If a valid entry is not found, return NULL. */
57484865Sobrienstruct ia64_opcode *
57584865Sobrienia64_dis_opcode (insn, type)
57684865Sobrien     ia64_insn insn;
57784865Sobrien     enum ia64_insn_type type;
57884865Sobrien{
57984865Sobrien  int disent = locate_opcode_ent (insn, type);
58084865Sobrien
58184865Sobrien  if (disent < 0)
58284865Sobrien    {
58384865Sobrien      return NULL;
58484865Sobrien    }
58584865Sobrien  else
58684865Sobrien    {
58784865Sobrien      unsigned int cb = ia64_dis_names[disent].completer_index;
58884865Sobrien      static char name[128];
58984865Sobrien      int place = ia64_dis_names[disent].insn_index;
59084865Sobrien      int ci = main_table[place].completers;
59184865Sobrien      ia64_insn tinsn = main_table[place].opcode;
59284865Sobrien
59384865Sobrien      strcpy (name, ia64_strings [main_table[place].name_index]);
59484865Sobrien
59584865Sobrien      while (cb)
59684865Sobrien	{
59784865Sobrien	  if (cb & 1)
59884865Sobrien	    {
59984865Sobrien	      int cname = completer_table[ci].name_index;
60084865Sobrien
60184865Sobrien	      tinsn = apply_completer (tinsn, ci);
60284865Sobrien
60384865Sobrien	      if (ia64_strings[cname][0] != '\0')
60484865Sobrien		{
60584865Sobrien		  strcat (name, ".");
60684865Sobrien		  strcat (name, ia64_strings[cname]);
60784865Sobrien		}
60884865Sobrien	      if (cb != 1)
60984865Sobrien		{
61084865Sobrien		  ci = completer_table[ci].subentries;
61184865Sobrien		}
61284865Sobrien	    }
61384865Sobrien	  else
61484865Sobrien	    {
61584865Sobrien	      ci = completer_table[ci].alternative;
61684865Sobrien	    }
61784865Sobrien	  if (ci < 0)
61884865Sobrien	    {
61984865Sobrien	      abort ();
62084865Sobrien	    }
62184865Sobrien	  cb = cb >> 1;
62284865Sobrien	}
62384865Sobrien      if (tinsn != (insn & main_table[place].mask))
62484865Sobrien	{
62584865Sobrien	  abort ();
62684865Sobrien	}
62789857Sobrien      return make_ia64_opcode (insn, name, place,
62884865Sobrien                               completer_table[ci].dependencies);
62984865Sobrien    }
63084865Sobrien}
63184865Sobrien
63284865Sobrien/* Search the main_opcode table starting from PLACE for an opcode that
63384865Sobrien   matches NAME.  Return NULL if one is not found. */
63484865Sobrien
63584865Sobrienstatic struct ia64_opcode *
63684865Sobrienia64_find_matching_opcode (name, place)
63784865Sobrien     const char *name;
63884865Sobrien     short place;
63984865Sobrien{
64084865Sobrien  char op[129];
64184865Sobrien  const char *suffix;
64284865Sobrien  short name_index;
64384865Sobrien
64484865Sobrien  if (strlen (name) > 128)
64584865Sobrien    {
64684865Sobrien      return NULL;
64784865Sobrien    }
64884865Sobrien  suffix = name;
64984865Sobrien  get_opc_prefix (&suffix, op);
65084865Sobrien  name_index = find_string_ent (op);
65184865Sobrien  if (name_index < 0)
65284865Sobrien    {
65384865Sobrien      return NULL;
65484865Sobrien    }
65584865Sobrien
65684865Sobrien  while (main_table[place].name_index == name_index)
65784865Sobrien    {
65884865Sobrien      const char *curr_suffix = suffix;
65984865Sobrien      ia64_insn curr_insn = main_table[place].opcode;
66084865Sobrien      short completer = -1;
66184865Sobrien
66284865Sobrien      do {
66389857Sobrien	if (suffix[0] == '\0')
66484865Sobrien	  {
66584865Sobrien	    completer = find_completer (place, completer, suffix);
66684865Sobrien	  }
66784865Sobrien	else
66884865Sobrien	  {
66984865Sobrien	    get_opc_prefix (&curr_suffix, op);
67084865Sobrien	    completer = find_completer (place, completer, op);
67184865Sobrien	  }
67284865Sobrien	if (completer != -1)
67384865Sobrien	  {
67484865Sobrien	    curr_insn = apply_completer (curr_insn, completer);
67584865Sobrien	  }
67684865Sobrien      } while (completer != -1 && curr_suffix[0] != '\0');
67784865Sobrien
67884865Sobrien      if (completer != -1 && curr_suffix[0] == '\0'
67984865Sobrien	  && completer_table[completer].terminal_completer)
68084865Sobrien	{
68184865Sobrien          int depind = completer_table[completer].dependencies;
68284865Sobrien	  return make_ia64_opcode (curr_insn, name, place, depind);
68384865Sobrien	}
68484865Sobrien      else
68584865Sobrien	{
68684865Sobrien	  place++;
68784865Sobrien	}
68884865Sobrien    }
68984865Sobrien  return NULL;
69084865Sobrien}
69184865Sobrien
69284865Sobrien/* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL
69384865Sobrien   if one does not exist.
69484865Sobrien
69584865Sobrien   It is the caller's responsibility to invoke ia64_free_opcode () to
69684865Sobrien   release any resources used by the returned entry. */
69784865Sobrien
69884865Sobrienstruct ia64_opcode *
69984865Sobrienia64_find_next_opcode (prev_ent)
70084865Sobrien     struct ia64_opcode *prev_ent;
70184865Sobrien{
70284865Sobrien  return ia64_find_matching_opcode (prev_ent->name,
70384865Sobrien				    prev_ent->ent_index + 1);
70484865Sobrien}
70584865Sobrien
70684865Sobrien/* Find the first opcode that matches NAME, or return NULL if it does
70784865Sobrien   not exist.
70884865Sobrien
70984865Sobrien   It is the caller's responsibility to invoke ia64_free_opcode () to
71084865Sobrien   release any resources used by the returned entry. */
71184865Sobrien
71284865Sobrienstruct ia64_opcode *
71384865Sobrienia64_find_opcode (name)
71484865Sobrien     const char *name;
71584865Sobrien{
71684865Sobrien  char op[129];
71784865Sobrien  const char *suffix;
71884865Sobrien  short place;
71984865Sobrien  short name_index;
72084865Sobrien
72184865Sobrien  if (strlen (name) > 128)
72284865Sobrien    {
72384865Sobrien      return NULL;
72484865Sobrien    }
72584865Sobrien  suffix = name;
72684865Sobrien  get_opc_prefix (&suffix, op);
72784865Sobrien  name_index = find_string_ent (op);
72884865Sobrien  if (name_index < 0)
72984865Sobrien    {
73084865Sobrien      return NULL;
73184865Sobrien    }
73284865Sobrien
73384865Sobrien  place = find_main_ent (name_index);
73484865Sobrien
73584865Sobrien  if (place < 0)
73684865Sobrien    {
73784865Sobrien      return NULL;
73884865Sobrien    }
73984865Sobrien  return ia64_find_matching_opcode (name, place);
74084865Sobrien}
74184865Sobrien
74284865Sobrien/* Free any resources used by ENT. */
74384865Sobrienvoid
74484865Sobrienia64_free_opcode (ent)
74584865Sobrien     struct ia64_opcode *ent;
74684865Sobrien{
74784865Sobrien  free ((void *)ent->name);
74884865Sobrien  free (ent);
74984865Sobrien}
75084865Sobrien
75184865Sobrienconst struct ia64_dependency *
75284865Sobrienia64_find_dependency (index)
75384865Sobrien  int index;
75484865Sobrien{
75584865Sobrien  index = DEP(index);
75684865Sobrien
75784865Sobrien  if (index < 0
75884865Sobrien      || index >= (int)(sizeof(dependencies) / sizeof(dependencies[0])))
75984865Sobrien    return NULL;
76084865Sobrien
76184865Sobrien  return &dependencies[index];
76284865Sobrien}
763