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