|  | /* ia64-opc.c -- Functions to access the compacted opcode table | 
|  | Copyright (C) 1999-2020 Free Software Foundation, Inc. | 
|  | Written by Bob Manson of Cygnus Solutions, <manson@cygnus.com> | 
|  |  | 
|  | This file is part of the GNU opcodes library. | 
|  |  | 
|  | This library is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | It is distributed in the hope that it will be useful, but WITHOUT | 
|  | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
|  | or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
|  | License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this file; see the file COPYING.  If not, write to the | 
|  | Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "libiberty.h" | 
|  | #include "ia64-asmtab.h" | 
|  | #include "ia64-asmtab.c" | 
|  |  | 
|  | static void get_opc_prefix (const char **, char *); | 
|  | static short int find_string_ent (const char *); | 
|  | static short int find_main_ent (short int); | 
|  | static short int find_completer (short int, short int, const char *); | 
|  | static ia64_insn apply_completer (ia64_insn, int); | 
|  | static int extract_op_bits (int, int, int); | 
|  | static int extract_op (int, int *, unsigned int *); | 
|  | static int opcode_verify (ia64_insn, int, enum ia64_insn_type); | 
|  | static int locate_opcode_ent (ia64_insn, enum ia64_insn_type); | 
|  | static struct ia64_opcode *make_ia64_opcode | 
|  | (ia64_insn, const char *, int, int); | 
|  | static struct ia64_opcode *ia64_find_matching_opcode | 
|  | (const char *, short int); | 
|  |  | 
|  | const struct ia64_templ_desc ia64_templ_desc[16] = | 
|  | { | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },	/* 0 */ | 
|  | { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" }, | 
|  | { 0, { 0, },				    "-3-" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },	/* 4 */ | 
|  | { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" },	/* 8 */ | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" }, | 
|  | { 0, { 0, },				    "-a-" }, | 
|  | { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" },	/* c */ | 
|  | { 0, { 0, },				    "-d-" }, | 
|  | { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" }, | 
|  | { 0, { 0, },				    "-f-" }, | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST. | 
|  | PTR will be adjusted to point to the start of the next portion | 
|  | of the opcode, or at the NUL character. */ | 
|  |  | 
|  | static void | 
|  | get_opc_prefix (const char **ptr, char *dest) | 
|  | { | 
|  | char *c = strchr (*ptr, '.'); | 
|  | if (c != NULL) | 
|  | { | 
|  | memcpy (dest, *ptr, c - *ptr); | 
|  | dest[c - *ptr] = '\0'; | 
|  | *ptr = c + 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | int l = strlen (*ptr); | 
|  | memcpy (dest, *ptr, l); | 
|  | dest[l] = '\0'; | 
|  | *ptr += l; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Find the index of the entry in the string table corresponding to | 
|  | STR; return -1 if one does not exist. */ | 
|  |  | 
|  | static short | 
|  | find_string_ent (const char *str) | 
|  | { | 
|  | short start = 0; | 
|  | short end = sizeof (ia64_strings) / sizeof (const char *); | 
|  | short i = (start + end) / 2; | 
|  |  | 
|  | if (strcmp (str, ia64_strings[end - 1]) > 0) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  | while (start <= end) | 
|  | { | 
|  | int c = strcmp (str, ia64_strings[i]); | 
|  | if (c < 0) | 
|  | { | 
|  | end = i - 1; | 
|  | } | 
|  | else if (c == 0) | 
|  | { | 
|  | return i; | 
|  | } | 
|  | else | 
|  | { | 
|  | start = i + 1; | 
|  | } | 
|  | i = (start + end) / 2; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Find the opcode in the main opcode table whose name is STRINGINDEX, or | 
|  | return -1 if one does not exist. */ | 
|  |  | 
|  | static short | 
|  | find_main_ent (short nameindex) | 
|  | { | 
|  | short start = 0; | 
|  | short end = ARRAY_SIZE (main_table); | 
|  | short i = (start + end) / 2; | 
|  |  | 
|  | if (nameindex < main_table[0].name_index | 
|  | || nameindex > main_table[end - 1].name_index) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  | while (start <= end) | 
|  | { | 
|  | if (nameindex < main_table[i].name_index) | 
|  | { | 
|  | end = i - 1; | 
|  | } | 
|  | else if (nameindex == main_table[i].name_index) | 
|  | { | 
|  | while (i > 0 && main_table[i - 1].name_index == nameindex) | 
|  | { | 
|  | i--; | 
|  | } | 
|  | return i; | 
|  | } | 
|  | else | 
|  | { | 
|  | start = i + 1; | 
|  | } | 
|  | i = (start + end) / 2; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Find the index of the entry in the completer table that is part of | 
|  | MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or | 
|  | return -1 if one does not exist. */ | 
|  |  | 
|  | static short | 
|  | find_completer (short main_ent, short prev_completer, const char *name) | 
|  | { | 
|  | short name_index = find_string_ent (name); | 
|  |  | 
|  | if (name_index < 0) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (prev_completer == -1) | 
|  | { | 
|  | prev_completer = main_table[main_ent].completers; | 
|  | } | 
|  | else | 
|  | { | 
|  | prev_completer = completer_table[prev_completer].subentries; | 
|  | } | 
|  |  | 
|  | while (prev_completer != -1) | 
|  | { | 
|  | if (completer_table[prev_completer].name_index == name_index) | 
|  | { | 
|  | return prev_completer; | 
|  | } | 
|  | prev_completer = completer_table[prev_completer].alternative; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and | 
|  | return the result. */ | 
|  |  | 
|  | static ia64_insn | 
|  | apply_completer (ia64_insn opcode, int completer_index) | 
|  | { | 
|  | ia64_insn mask = completer_table[completer_index].mask; | 
|  | ia64_insn bits = completer_table[completer_index].bits; | 
|  | int shiftamt = (completer_table[completer_index].offset & 63); | 
|  |  | 
|  | mask = mask << shiftamt; | 
|  | bits = bits << shiftamt; | 
|  | opcode = (opcode & ~mask) | bits; | 
|  | return opcode; | 
|  | } | 
|  |  | 
|  | /* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in | 
|  | the dis_table array, and return its value.  (BITOFFSET is numbered | 
|  | starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the | 
|  | first byte in OP_POINTER.) */ | 
|  |  | 
|  | static int | 
|  | extract_op_bits (int op_pointer, int bitoffset, int bits) | 
|  | { | 
|  | int res = 0; | 
|  |  | 
|  | op_pointer += (bitoffset / 8); | 
|  |  | 
|  | if (bitoffset % 8) | 
|  | { | 
|  | unsigned int op = dis_table[op_pointer++]; | 
|  | int numb = 8 - (bitoffset % 8); | 
|  | int mask = (1 << numb) - 1; | 
|  | int bata = (bits < numb) ? bits : numb; | 
|  | int delta = numb - bata; | 
|  |  | 
|  | res = (res << bata) | ((op & mask) >> delta); | 
|  | bitoffset += bata; | 
|  | bits -= bata; | 
|  | } | 
|  | while (bits >= 8) | 
|  | { | 
|  | res = (res << 8) | (dis_table[op_pointer++] & 255); | 
|  | bits -= 8; | 
|  | } | 
|  | if (bits > 0) | 
|  | { | 
|  | unsigned int op = (dis_table[op_pointer++] & 255); | 
|  | res = (res << bits) | (op >> (8 - bits)); | 
|  | } | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* Examine the state machine entry at OP_POINTER in the dis_table | 
|  | array, and extract its values into OPVAL and OP.  The length of the | 
|  | state entry in bits is returned. */ | 
|  |  | 
|  | static int | 
|  | extract_op (int op_pointer, int *opval, unsigned int *op) | 
|  | { | 
|  | int oplen = 5; | 
|  |  | 
|  | *op = dis_table[op_pointer]; | 
|  |  | 
|  | if ((*op) & 0x40) | 
|  | { | 
|  | opval[0] = extract_op_bits (op_pointer, oplen, 5); | 
|  | oplen += 5; | 
|  | } | 
|  | switch ((*op) & 0x30) | 
|  | { | 
|  | case 0x10: | 
|  | { | 
|  | opval[1] = extract_op_bits (op_pointer, oplen, 8); | 
|  | oplen += 8; | 
|  | opval[1] += op_pointer; | 
|  | break; | 
|  | } | 
|  | case 0x20: | 
|  | { | 
|  | opval[1] = extract_op_bits (op_pointer, oplen, 16); | 
|  | if (! (opval[1] & 32768)) | 
|  | { | 
|  | opval[1] += op_pointer; | 
|  | } | 
|  | oplen += 16; | 
|  | break; | 
|  | } | 
|  | case 0x30: | 
|  | { | 
|  | oplen--; | 
|  | opval[2] = extract_op_bits (op_pointer, oplen, 12); | 
|  | oplen += 12; | 
|  | opval[2] |= 32768; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (((*op) & 0x08) && (((*op) & 0x30) != 0x30)) | 
|  | { | 
|  | opval[2] = extract_op_bits (op_pointer, oplen, 16); | 
|  | oplen += 16; | 
|  | if (! (opval[2] & 32768)) | 
|  | { | 
|  | opval[2] += op_pointer; | 
|  | } | 
|  | } | 
|  | return oplen; | 
|  | } | 
|  |  | 
|  | /* Returns a non-zero value if the opcode in the main_table list at | 
|  | PLACE matches OPCODE and is of type TYPE. */ | 
|  |  | 
|  | static int | 
|  | opcode_verify (ia64_insn opcode, int place, enum ia64_insn_type type) | 
|  | { | 
|  | if (main_table[place].opcode_type != type) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | if (main_table[place].flags | 
|  | & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT)) | 
|  | { | 
|  | const struct ia64_operand *o1, *o2; | 
|  | ia64_insn f2, f3; | 
|  |  | 
|  | if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3) | 
|  | { | 
|  | o1 = elf64_ia64_operands + IA64_OPND_F2; | 
|  | o2 = elf64_ia64_operands + IA64_OPND_F3; | 
|  | (*o1->extract) (o1, opcode, &f2); | 
|  | (*o2->extract) (o2, opcode, &f3); | 
|  | if (f2 != f3) | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | ia64_insn len, count; | 
|  |  | 
|  | /* length must equal 64-count: */ | 
|  | o1 = elf64_ia64_operands + IA64_OPND_LEN6; | 
|  | o2 = elf64_ia64_operands + main_table[place].operands[2]; | 
|  | (*o1->extract) (o1, opcode, &len); | 
|  | (*o2->extract) (o2, opcode, &count); | 
|  | if (len != 64 - count) | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Find an instruction entry in the ia64_dis_names array that matches | 
|  | opcode OPCODE and is of type TYPE.  Returns either a positive index | 
|  | into the array, or a negative value if an entry for OPCODE could | 
|  | not be found.  Checks all matches and returns the one with the highest | 
|  | priority. */ | 
|  |  | 
|  | static int | 
|  | locate_opcode_ent (ia64_insn opcode, enum ia64_insn_type type) | 
|  | { | 
|  | int currtest[41]; | 
|  | int bitpos[41]; | 
|  | int op_ptr[41]; | 
|  | int currstatenum = 0; | 
|  | short found_disent = -1; | 
|  | short found_priority = -1; | 
|  |  | 
|  | currtest[currstatenum] = 0; | 
|  | op_ptr[currstatenum] = 0; | 
|  | bitpos[currstatenum] = 40; | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | int op_pointer = op_ptr[currstatenum]; | 
|  | unsigned int op; | 
|  | int currbitnum = bitpos[currstatenum]; | 
|  | int oplen; | 
|  | int opval[3] = {0}; | 
|  | int next_op; | 
|  | int currbit; | 
|  |  | 
|  | oplen = extract_op (op_pointer, opval, &op); | 
|  |  | 
|  | bitpos[currstatenum] = currbitnum; | 
|  |  | 
|  | /* Skip opval[0] bits in the instruction.  */ | 
|  | if (op & 0x40) | 
|  | { | 
|  | currbitnum -= opval[0]; | 
|  | } | 
|  |  | 
|  | if (currbitnum < 0) | 
|  | currbitnum = 0; | 
|  |  | 
|  | /* The value of the current bit being tested.  */ | 
|  | currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0; | 
|  | next_op = -1; | 
|  |  | 
|  | /* We always perform the tests specified in the current state in | 
|  | a particular order, falling through to the next test if the | 
|  | previous one failed. */ | 
|  | switch (currtest[currstatenum]) | 
|  | { | 
|  | case 0: | 
|  | currtest[currstatenum]++; | 
|  | if (currbit == 0 && (op & 0x80)) | 
|  | { | 
|  | /* Check for a zero bit.  If this test solely checks for | 
|  | a zero bit, we can check for up to 8 consecutive zero | 
|  | bits (the number to check is specified by the lower 3 | 
|  | bits in the state code.) | 
|  |  | 
|  | If the state instruction matches, we go to the very | 
|  | next state instruction; otherwise, try the next test. */ | 
|  |  | 
|  | if ((op & 0xf8) == 0x80) | 
|  | { | 
|  | int count = op & 0x7; | 
|  | int x; | 
|  |  | 
|  | for (x = 0; x <= count; x++) | 
|  | { | 
|  | int i = | 
|  | opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0; | 
|  | if (i) | 
|  | { | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (x > count) | 
|  | { | 
|  | next_op = op_pointer + ((oplen + 7) / 8); | 
|  | currbitnum -= count; | 
|  | break; | 
|  | } | 
|  | } | 
|  | else if (! currbit) | 
|  | { | 
|  | next_op = op_pointer + ((oplen + 7) / 8); | 
|  | break; | 
|  | } | 
|  | } | 
|  | /* FALLTHROUGH */ | 
|  | case 1: | 
|  | /* If the bit in the instruction is one, go to the state | 
|  | instruction specified by opval[1]. */ | 
|  | currtest[currstatenum]++; | 
|  | if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30)) | 
|  | { | 
|  | next_op = opval[1]; | 
|  | break; | 
|  | } | 
|  | /* FALLTHROUGH */ | 
|  | case 2: | 
|  | /* Don't care.  Skip the current bit and go to the state | 
|  | instruction specified by opval[2]. | 
|  |  | 
|  | An encoding of 0x30 is special; this means that a 12-bit | 
|  | offset into the ia64_dis_names[] array is specified.  */ | 
|  | currtest[currstatenum]++; | 
|  | if ((op & 0x08) || ((op & 0x30) == 0x30)) | 
|  | { | 
|  | next_op = opval[2]; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* If bit 15 is set in the address of the next state, an offset | 
|  | in the ia64_dis_names array was specified instead.  We then | 
|  | check to see if an entry in the list of opcodes matches the | 
|  | opcode we were given; if so, we have succeeded.  */ | 
|  |  | 
|  | if ((next_op >= 0) && (next_op & 32768)) | 
|  | { | 
|  | short disent = next_op & 32767; | 
|  | short priority = -1; | 
|  |  | 
|  | if (next_op > 65535) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Run through the list of opcodes to check, trying to find | 
|  | one that matches.  */ | 
|  | while (disent >= 0) | 
|  | { | 
|  | int place = ia64_dis_names[disent].insn_index; | 
|  |  | 
|  | priority = ia64_dis_names[disent].priority; | 
|  |  | 
|  | if (opcode_verify (opcode, place, type) | 
|  | && priority > found_priority) | 
|  | { | 
|  | break; | 
|  | } | 
|  | if (ia64_dis_names[disent].next_flag) | 
|  | { | 
|  | disent++; | 
|  | } | 
|  | else | 
|  | { | 
|  | disent = -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (disent >= 0) | 
|  | { | 
|  | found_disent = disent; | 
|  | found_priority = priority; | 
|  | } | 
|  | /* Try the next test in this state, regardless of whether a match | 
|  | was found. */ | 
|  | next_op = -2; | 
|  | } | 
|  |  | 
|  | /* next_op == -1 is "back up to the previous state". | 
|  | next_op == -2 is "stay in this state and try the next test". | 
|  | Otherwise, transition to the state indicated by next_op. */ | 
|  |  | 
|  | if (next_op == -1) | 
|  | { | 
|  | currstatenum--; | 
|  | if (currstatenum < 0) | 
|  | { | 
|  | return found_disent; | 
|  | } | 
|  | } | 
|  | else if (next_op >= 0) | 
|  | { | 
|  | currstatenum++; | 
|  | bitpos[currstatenum] = currbitnum - 1; | 
|  | op_ptr[currstatenum] = next_op; | 
|  | currtest[currstatenum] = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */ | 
|  |  | 
|  | static struct ia64_opcode * | 
|  | make_ia64_opcode (ia64_insn opcode, const char *name, int place, int depind) | 
|  | { | 
|  | struct ia64_opcode *res = | 
|  | (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode)); | 
|  | res->name = xstrdup (name); | 
|  | res->type = main_table[place].opcode_type; | 
|  | res->num_outputs = main_table[place].num_outputs; | 
|  | res->opcode = opcode; | 
|  | res->mask = main_table[place].mask; | 
|  | res->operands[0] = main_table[place].operands[0]; | 
|  | res->operands[1] = main_table[place].operands[1]; | 
|  | res->operands[2] = main_table[place].operands[2]; | 
|  | res->operands[3] = main_table[place].operands[3]; | 
|  | res->operands[4] = main_table[place].operands[4]; | 
|  | res->flags = main_table[place].flags; | 
|  | res->ent_index = place; | 
|  | res->dependencies = &op_dependencies[depind]; | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* Determine the ia64_opcode entry for the opcode specified by INSN | 
|  | and TYPE.  If a valid entry is not found, return NULL. */ | 
|  | struct ia64_opcode * | 
|  | ia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type) | 
|  | { | 
|  | int disent = locate_opcode_ent (insn, type); | 
|  |  | 
|  | if (disent < 0) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | unsigned int cb = ia64_dis_names[disent].completer_index; | 
|  | static char name[128]; | 
|  | int place = ia64_dis_names[disent].insn_index; | 
|  | int ci = main_table[place].completers; | 
|  | ia64_insn tinsn = main_table[place].opcode; | 
|  |  | 
|  | strcpy (name, ia64_strings [main_table[place].name_index]); | 
|  |  | 
|  | while (cb) | 
|  | { | 
|  | if (cb & 1) | 
|  | { | 
|  | int cname = completer_table[ci].name_index; | 
|  |  | 
|  | tinsn = apply_completer (tinsn, ci); | 
|  |  | 
|  | if (ia64_strings[cname][0] != '\0') | 
|  | { | 
|  | strcat (name, "."); | 
|  | strcat (name, ia64_strings[cname]); | 
|  | } | 
|  | if (cb != 1) | 
|  | { | 
|  | ci = completer_table[ci].subentries; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | ci = completer_table[ci].alternative; | 
|  | } | 
|  | if (ci < 0) | 
|  | { | 
|  | abort (); | 
|  | } | 
|  | cb = cb >> 1; | 
|  | } | 
|  | if (tinsn != (insn & main_table[place].mask)) | 
|  | { | 
|  | abort (); | 
|  | } | 
|  | return make_ia64_opcode (insn, name, place, | 
|  | completer_table[ci].dependencies); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Search the main_opcode table starting from PLACE for an opcode that | 
|  | matches NAME.  Return NULL if one is not found. */ | 
|  |  | 
|  | static struct ia64_opcode * | 
|  | ia64_find_matching_opcode (const char *name, short place) | 
|  | { | 
|  | char op[129]; | 
|  | const char *suffix; | 
|  | short name_index; | 
|  |  | 
|  | if ((unsigned) place >= ARRAY_SIZE (main_table)) | 
|  | return NULL; | 
|  |  | 
|  | if (strlen (name) > 128) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | suffix = name; | 
|  | get_opc_prefix (&suffix, op); | 
|  | name_index = find_string_ent (op); | 
|  | if (name_index < 0) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | while (main_table[place].name_index == name_index) | 
|  | { | 
|  | const char *curr_suffix = suffix; | 
|  | ia64_insn curr_insn = main_table[place].opcode; | 
|  | short completer = -1; | 
|  |  | 
|  | do { | 
|  | if (suffix[0] == '\0') | 
|  | { | 
|  | completer = find_completer (place, completer, suffix); | 
|  | } | 
|  | else | 
|  | { | 
|  | get_opc_prefix (&curr_suffix, op); | 
|  | completer = find_completer (place, completer, op); | 
|  | } | 
|  | if (completer != -1) | 
|  | { | 
|  | curr_insn = apply_completer (curr_insn, completer); | 
|  | } | 
|  | } while (completer != -1 && curr_suffix[0] != '\0'); | 
|  |  | 
|  | if (completer != -1 && curr_suffix[0] == '\0' | 
|  | && completer_table[completer].terminal_completer) | 
|  | { | 
|  | int depind = completer_table[completer].dependencies; | 
|  | return make_ia64_opcode (curr_insn, name, place, depind); | 
|  | } | 
|  | else | 
|  | { | 
|  | place++; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL | 
|  | if one does not exist. | 
|  |  | 
|  | It is the caller's responsibility to invoke ia64_free_opcode () to | 
|  | release any resources used by the returned entry. */ | 
|  |  | 
|  | struct ia64_opcode * | 
|  | ia64_find_next_opcode (struct ia64_opcode *prev_ent) | 
|  | { | 
|  | return ia64_find_matching_opcode (prev_ent->name, | 
|  | prev_ent->ent_index + 1); | 
|  | } | 
|  |  | 
|  | /* Find the first opcode that matches NAME, or return NULL if it does | 
|  | not exist. | 
|  |  | 
|  | It is the caller's responsibility to invoke ia64_free_opcode () to | 
|  | release any resources used by the returned entry. */ | 
|  |  | 
|  | struct ia64_opcode * | 
|  | ia64_find_opcode (const char *name) | 
|  | { | 
|  | char op[129]; | 
|  | const char *suffix; | 
|  | short place; | 
|  | short name_index; | 
|  |  | 
|  | if (strlen (name) > 128) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | suffix = name; | 
|  | get_opc_prefix (&suffix, op); | 
|  | name_index = find_string_ent (op); | 
|  | if (name_index < 0) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | place = find_main_ent (name_index); | 
|  |  | 
|  | if (place < 0) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | return ia64_find_matching_opcode (name, place); | 
|  | } | 
|  |  | 
|  | /* Free any resources used by ENT. */ | 
|  | void | 
|  | ia64_free_opcode (struct ia64_opcode *ent) | 
|  | { | 
|  | free ((void *)ent->name); | 
|  | free (ent); | 
|  | } | 
|  |  | 
|  | const struct ia64_dependency * | 
|  | ia64_find_dependency (int dep_index) | 
|  | { | 
|  | dep_index = DEP(dep_index); | 
|  |  | 
|  | if (dep_index < 0 | 
|  | || dep_index >= (int) ARRAY_SIZE (dependencies)) | 
|  | return NULL; | 
|  |  | 
|  | return &dependencies[dep_index]; | 
|  | } |