Back to index

cell-binutils  2.17cvs20070401
ia64-opc.c
Go to the documentation of this file.
00001 /* ia64-opc.c -- Functions to access the compacted opcode table
00002    Copyright 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
00003    Written by Bob Manson of Cygnus Solutions, <manson@cygnus.com>
00004 
00005    This file is part of GDB, GAS, and the GNU binutils.
00006 
00007    GDB, GAS, and the GNU binutils are free software; you can redistribute
00008    them and/or modify them under the terms of the GNU General Public
00009    License as published by the Free Software Foundation; either version
00010    2, or (at your option) any later version.
00011 
00012    GDB, GAS, and the GNU binutils are distributed in the hope that they
00013    will be useful, but WITHOUT ANY WARRANTY; without even the implied
00014    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
00015    the GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this file; see the file COPYING.  If not, write to the
00019    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00020    02110-1301, USA.  */
00021 
00022 #include "ansidecl.h"
00023 #include "sysdep.h"
00024 #include "libiberty.h"
00025 #include "ia64-asmtab.h"
00026 #include "ia64-asmtab.c"
00027 
00028 static void get_opc_prefix (const char **, char *);
00029 static short int find_string_ent (const char *);
00030 static short int find_main_ent (short int);
00031 static short int find_completer (short int, short int, const char *);
00032 static ia64_insn apply_completer (ia64_insn, int);
00033 static int extract_op_bits (int, int, int);
00034 static int extract_op (int, int *, unsigned int *);
00035 static int opcode_verify (ia64_insn, int, enum ia64_insn_type);
00036 static int locate_opcode_ent (ia64_insn, enum ia64_insn_type);
00037 static struct ia64_opcode *make_ia64_opcode
00038   (ia64_insn, const char *, int, int);
00039 static struct ia64_opcode *ia64_find_matching_opcode
00040   (const char *, short int);
00041 
00042 const struct ia64_templ_desc ia64_templ_desc[16] =
00043   {
00044     { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },   /* 0 */
00045     { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },
00046     { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" },
00047     { 0, { 0, },                              "-3-" },
00048     { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },   /* 4 */
00049     { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },
00050     { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" },
00051     { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" },
00052     { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" },   /* 8 */
00053     { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" },
00054     { 0, { 0, },                              "-a-" },
00055     { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" },
00056     { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" },   /* c */
00057     { 0, { 0, },                              "-d-" },
00058     { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" },
00059     { 0, { 0, },                              "-f-" },
00060   };
00061 
00062 
00063 /* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST.
00064    PTR will be adjusted to point to the start of the next portion
00065    of the opcode, or at the NUL character. */
00066 
00067 static void
00068 get_opc_prefix (const char **ptr, char *dest)
00069 {
00070   char *c = strchr (*ptr, '.');
00071   if (c != NULL)
00072     {
00073       memcpy (dest, *ptr, c - *ptr);
00074       dest[c - *ptr] = '\0';
00075       *ptr = c + 1;
00076     }
00077   else
00078     {
00079       int l = strlen (*ptr);
00080       memcpy (dest, *ptr, l);
00081       dest[l] = '\0';
00082       *ptr += l;
00083     }
00084 }
00085 
00086 /* Find the index of the entry in the string table corresponding to
00087    STR; return -1 if one does not exist. */
00088 
00089 static short
00090 find_string_ent (const char *str)
00091 {
00092   short start = 0;
00093   short end = sizeof (ia64_strings) / sizeof (const char *);
00094   short i = (start + end) / 2;
00095 
00096   if (strcmp (str, ia64_strings[end - 1]) > 0)
00097     {
00098       return -1;
00099     }
00100   while (start <= end)
00101     {
00102       int c = strcmp (str, ia64_strings[i]);
00103       if (c < 0)
00104        {
00105          end = i - 1;
00106        }
00107       else if (c == 0)
00108        {
00109          return i;
00110        }
00111       else
00112        {
00113          start = i + 1;
00114        }
00115       i = (start + end) / 2;
00116     }
00117   return -1;
00118 }
00119 
00120 /* Find the opcode in the main opcode table whose name is STRINGINDEX, or
00121    return -1 if one does not exist. */
00122 
00123 static short
00124 find_main_ent (short nameindex)
00125 {
00126   short start = 0;
00127   short end = sizeof (main_table) / sizeof (struct ia64_main_table);
00128   short i = (start + end) / 2;
00129 
00130   if (nameindex < main_table[0].name_index
00131       || nameindex > main_table[end - 1].name_index)
00132     {
00133       return -1;
00134     }
00135   while (start <= end)
00136     {
00137       if (nameindex < main_table[i].name_index)
00138        {
00139          end = i - 1;
00140        }
00141       else if (nameindex == main_table[i].name_index)
00142        {
00143          while (i > 0 && main_table[i - 1].name_index == nameindex)
00144            {
00145              i--;
00146            }
00147          return i;
00148        }
00149       else
00150        {
00151          start = i + 1;
00152        }
00153       i = (start + end) / 2;
00154     }
00155   return -1;
00156 }
00157 
00158 /* Find the index of the entry in the completer table that is part of
00159    MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or
00160    return -1 if one does not exist. */
00161 
00162 static short
00163 find_completer (short main_ent, short prev_completer, const char *name)
00164 {
00165   short name_index = find_string_ent (name);
00166 
00167   if (name_index < 0)
00168     {
00169       return -1;
00170     }
00171 
00172   if (prev_completer == -1)
00173     {
00174       prev_completer = main_table[main_ent].completers;
00175     }
00176   else
00177     {
00178       prev_completer = completer_table[prev_completer].subentries;
00179     }
00180 
00181   while (prev_completer != -1)
00182     {
00183       if (completer_table[prev_completer].name_index == name_index)
00184        {
00185          return prev_completer;
00186        }
00187       prev_completer = completer_table[prev_completer].alternative;
00188     }
00189   return -1;
00190 }
00191 
00192 /* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and
00193    return the result. */
00194 
00195 static ia64_insn
00196 apply_completer (ia64_insn opcode, int completer_index)
00197 {
00198   ia64_insn mask = completer_table[completer_index].mask;
00199   ia64_insn bits = completer_table[completer_index].bits;
00200   int shiftamt = (completer_table[completer_index].offset & 63);
00201 
00202   mask = mask << shiftamt;
00203   bits = bits << shiftamt;
00204   opcode = (opcode & ~mask) | bits;
00205   return opcode;
00206 }
00207 
00208 /* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in
00209    the dis_table array, and return its value.  (BITOFFSET is numbered
00210    starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the
00211    first byte in OP_POINTER.) */
00212 
00213 static int
00214 extract_op_bits (int op_pointer, int bitoffset, int bits)
00215 {
00216   int res = 0;
00217 
00218   op_pointer += (bitoffset / 8);
00219 
00220   if (bitoffset % 8)
00221     {
00222       unsigned int op = dis_table[op_pointer++];
00223       int numb = 8 - (bitoffset % 8);
00224       int mask = (1 << numb) - 1;
00225       int bata = (bits < numb) ? bits : numb;
00226       int delta = numb - bata;
00227 
00228       res = (res << bata) | ((op & mask) >> delta);
00229       bitoffset += bata;
00230       bits -= bata;
00231     }
00232   while (bits >= 8)
00233     {
00234       res = (res << 8) | (dis_table[op_pointer++] & 255);
00235       bits -= 8;
00236     }
00237   if (bits > 0)
00238     {
00239       unsigned int op = (dis_table[op_pointer++] & 255);
00240       res = (res << bits) | (op >> (8 - bits));
00241     }
00242   return res;
00243 }
00244 
00245 /* Examine the state machine entry at OP_POINTER in the dis_table
00246    array, and extract its values into OPVAL and OP.  The length of the
00247    state entry in bits is returned. */
00248 
00249 static int
00250 extract_op (int op_pointer, int *opval, unsigned int *op)
00251 {
00252   int oplen = 5;
00253 
00254   *op = dis_table[op_pointer];
00255 
00256   if ((*op) & 0x40)
00257     {
00258       opval[0] = extract_op_bits (op_pointer, oplen, 5);
00259       oplen += 5;
00260     }
00261   switch ((*op) & 0x30)
00262     {
00263     case 0x10:
00264       {
00265        opval[1] = extract_op_bits (op_pointer, oplen, 8);
00266        oplen += 8;
00267        opval[1] += op_pointer;
00268        break;
00269       }
00270     case 0x20:
00271       {
00272        opval[1] = extract_op_bits (op_pointer, oplen, 16);
00273        if (! (opval[1] & 32768))
00274          {
00275            opval[1] += op_pointer;
00276          }
00277        oplen += 16;
00278        break;
00279       }
00280     case 0x30:
00281       {
00282        oplen--;
00283        opval[2] = extract_op_bits (op_pointer, oplen, 12);
00284        oplen += 12;
00285        opval[2] |= 32768;
00286        break;
00287       }
00288     }
00289   if (((*op) & 0x08) && (((*op) & 0x30) != 0x30))
00290     {
00291       opval[2] = extract_op_bits (op_pointer, oplen, 16);
00292       oplen += 16;
00293       if (! (opval[2] & 32768))
00294        {
00295          opval[2] += op_pointer;
00296        }
00297     }
00298   return oplen;
00299 }
00300 
00301 /* Returns a non-zero value if the opcode in the main_table list at
00302    PLACE matches OPCODE and is of type TYPE. */
00303 
00304 static int
00305 opcode_verify (ia64_insn opcode, int place, enum ia64_insn_type type)
00306 {
00307   if (main_table[place].opcode_type != type)
00308     {
00309       return 0;
00310     }
00311   if (main_table[place].flags
00312       & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT))
00313     {
00314       const struct ia64_operand *o1, *o2;
00315       ia64_insn f2, f3;
00316 
00317       if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3)
00318        {
00319          o1 = elf64_ia64_operands + IA64_OPND_F2;
00320          o2 = elf64_ia64_operands + IA64_OPND_F3;
00321          (*o1->extract) (o1, opcode, &f2);
00322          (*o2->extract) (o2, opcode, &f3);
00323          if (f2 != f3)
00324            return 0;
00325        }
00326       else
00327        {
00328          ia64_insn len, count;
00329 
00330          /* length must equal 64-count: */
00331          o1 = elf64_ia64_operands + IA64_OPND_LEN6;
00332          o2 = elf64_ia64_operands + main_table[place].operands[2];
00333          (*o1->extract) (o1, opcode, &len);
00334          (*o2->extract) (o2, opcode, &count);
00335          if (len != 64 - count)
00336            return 0;
00337        }
00338     }
00339   return 1;
00340 }
00341 
00342 /* Find an instruction entry in the ia64_dis_names array that matches
00343    opcode OPCODE and is of type TYPE.  Returns either a positive index
00344    into the array, or a negative value if an entry for OPCODE could
00345    not be found.  Checks all matches and returns the one with the highest
00346    priority. */
00347 
00348 static int
00349 locate_opcode_ent (ia64_insn opcode, enum ia64_insn_type type)
00350 {
00351   int currtest[41];
00352   int bitpos[41];
00353   int op_ptr[41];
00354   int currstatenum = 0;
00355   short found_disent = -1;
00356   short found_priority = -1;
00357 
00358   currtest[currstatenum] = 0;
00359   op_ptr[currstatenum] = 0;
00360   bitpos[currstatenum] = 40;
00361 
00362   while (1)
00363     {
00364       int op_pointer = op_ptr[currstatenum];
00365       unsigned int op;
00366       int currbitnum = bitpos[currstatenum];
00367       int oplen;
00368       int opval[3] = {0};
00369       int next_op;
00370       int currbit;
00371 
00372       oplen = extract_op (op_pointer, opval, &op);
00373 
00374       bitpos[currstatenum] = currbitnum;
00375 
00376       /* Skip opval[0] bits in the instruction. */
00377       if (op & 0x40)
00378        {
00379          currbitnum -= opval[0];
00380        }
00381 
00382       /* The value of the current bit being tested. */
00383       currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0;
00384       next_op = -1;
00385 
00386       /* We always perform the tests specified in the current state in
00387         a particular order, falling through to the next test if the
00388         previous one failed. */
00389       switch (currtest[currstatenum])
00390        {
00391        case 0:
00392          currtest[currstatenum]++;
00393          if (currbit == 0 && (op & 0x80))
00394            {
00395              /* Check for a zero bit.  If this test solely checks for
00396                a zero bit, we can check for up to 8 consecutive zero
00397                bits (the number to check is specified by the lower 3
00398                bits in the state code.)
00399 
00400                If the state instruction matches, we go to the very
00401                next state instruction; otherwise, try the next test. */
00402 
00403              if ((op & 0xf8) == 0x80)
00404               {
00405                 int count = op & 0x7;
00406                 int x;
00407 
00408                 for (x = 0; x <= count; x++)
00409                   {
00410                     int i =
00411                      opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0;
00412                     if (i)
00413                      {
00414                        break;
00415                      }
00416                   }
00417                 if (x > count)
00418                   {
00419                     next_op = op_pointer + ((oplen + 7) / 8);
00420                     currbitnum -= count;
00421                     break;
00422                   }
00423               }
00424              else if (! currbit)
00425               {
00426                 next_op = op_pointer + ((oplen + 7) / 8);
00427                 break;
00428               }
00429            }
00430          /* FALLTHROUGH */
00431        case 1:
00432          /* If the bit in the instruction is one, go to the state
00433             instruction specified by opval[1]. */
00434          currtest[currstatenum]++;
00435          if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30))
00436            {
00437              next_op = opval[1];
00438              break;
00439            }
00440          /* FALLTHROUGH */
00441        case 2:
00442          /* Don't care.  Skip the current bit and go to the state
00443             instruction specified by opval[2].
00444 
00445             An encoding of 0x30 is special; this means that a 12-bit
00446             offset into the ia64_dis_names[] array is specified.  */
00447          currtest[currstatenum]++;
00448          if ((op & 0x08) || ((op & 0x30) == 0x30))
00449            {
00450              next_op = opval[2];
00451              break;
00452            }
00453        }
00454 
00455       /* If bit 15 is set in the address of the next state, an offset
00456         in the ia64_dis_names array was specified instead.  We then
00457         check to see if an entry in the list of opcodes matches the
00458         opcode we were given; if so, we have succeeded.  */
00459 
00460       if ((next_op >= 0) && (next_op & 32768))
00461        {
00462          short disent = next_op & 32767;
00463           short priority = -1;
00464 
00465          if (next_op > 65535)
00466            {
00467              abort ();
00468            }
00469 
00470          /* Run through the list of opcodes to check, trying to find
00471             one that matches.  */
00472          while (disent >= 0)
00473            {
00474              int place = ia64_dis_names[disent].insn_index;
00475 
00476               priority = ia64_dis_names[disent].priority;
00477 
00478              if (opcode_verify (opcode, place, type)
00479                   && priority > found_priority)
00480               {
00481                 break;
00482               }
00483              if (ia64_dis_names[disent].next_flag)
00484               {
00485                 disent++;
00486               }
00487              else
00488               {
00489                 disent = -1;
00490               }
00491            }
00492 
00493          if (disent >= 0)
00494            {
00495               found_disent = disent;
00496               found_priority = priority;
00497            }
00498           /* Try the next test in this state, regardless of whether a match
00499              was found. */
00500           next_op = -2;
00501        }
00502 
00503       /* next_op == -1 is "back up to the previous state".
00504         next_op == -2 is "stay in this state and try the next test".
00505         Otherwise, transition to the state indicated by next_op. */
00506 
00507       if (next_op == -1)
00508        {
00509          currstatenum--;
00510          if (currstatenum < 0)
00511            {
00512               return found_disent;
00513            }
00514        }
00515       else if (next_op >= 0)
00516        {
00517          currstatenum++;
00518          bitpos[currstatenum] = currbitnum - 1;
00519          op_ptr[currstatenum] = next_op;
00520          currtest[currstatenum] = 0;
00521        }
00522     }
00523 }
00524 
00525 /* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */
00526 
00527 static struct ia64_opcode *
00528 make_ia64_opcode (ia64_insn opcode, const char *name, int place, int depind)
00529 {
00530   struct ia64_opcode *res =
00531     (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode));
00532   res->name = xstrdup (name);
00533   res->type = main_table[place].opcode_type;
00534   res->num_outputs = main_table[place].num_outputs;
00535   res->opcode = opcode;
00536   res->mask = main_table[place].mask;
00537   res->operands[0] = main_table[place].operands[0];
00538   res->operands[1] = main_table[place].operands[1];
00539   res->operands[2] = main_table[place].operands[2];
00540   res->operands[3] = main_table[place].operands[3];
00541   res->operands[4] = main_table[place].operands[4];
00542   res->flags = main_table[place].flags;
00543   res->ent_index = place;
00544   res->dependencies = &op_dependencies[depind];
00545   return res;
00546 }
00547 
00548 /* Determine the ia64_opcode entry for the opcode specified by INSN
00549    and TYPE.  If a valid entry is not found, return NULL. */
00550 struct ia64_opcode *
00551 ia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type)
00552 {
00553   int disent = locate_opcode_ent (insn, type);
00554 
00555   if (disent < 0)
00556     {
00557       return NULL;
00558     }
00559   else
00560     {
00561       unsigned int cb = ia64_dis_names[disent].completer_index;
00562       static char name[128];
00563       int place = ia64_dis_names[disent].insn_index;
00564       int ci = main_table[place].completers;
00565       ia64_insn tinsn = main_table[place].opcode;
00566 
00567       strcpy (name, ia64_strings [main_table[place].name_index]);
00568 
00569       while (cb)
00570        {
00571          if (cb & 1)
00572            {
00573              int cname = completer_table[ci].name_index;
00574 
00575              tinsn = apply_completer (tinsn, ci);
00576 
00577              if (ia64_strings[cname][0] != '\0')
00578               {
00579                 strcat (name, ".");
00580                 strcat (name, ia64_strings[cname]);
00581               }
00582              if (cb != 1)
00583               {
00584                 ci = completer_table[ci].subentries;
00585               }
00586            }
00587          else
00588            {
00589              ci = completer_table[ci].alternative;
00590            }
00591          if (ci < 0)
00592            {
00593              abort ();
00594            }
00595          cb = cb >> 1;
00596        }
00597       if (tinsn != (insn & main_table[place].mask))
00598        {
00599          abort ();
00600        }
00601       return make_ia64_opcode (insn, name, place,
00602                                completer_table[ci].dependencies);
00603     }
00604 }
00605 
00606 /* Search the main_opcode table starting from PLACE for an opcode that
00607    matches NAME.  Return NULL if one is not found. */
00608 
00609 static struct ia64_opcode *
00610 ia64_find_matching_opcode (const char *name, short place)
00611 {
00612   char op[129];
00613   const char *suffix;
00614   short name_index;
00615 
00616   if (strlen (name) > 128)
00617     {
00618       return NULL;
00619     }
00620   suffix = name;
00621   get_opc_prefix (&suffix, op);
00622   name_index = find_string_ent (op);
00623   if (name_index < 0)
00624     {
00625       return NULL;
00626     }
00627 
00628   while (main_table[place].name_index == name_index)
00629     {
00630       const char *curr_suffix = suffix;
00631       ia64_insn curr_insn = main_table[place].opcode;
00632       short completer = -1;
00633 
00634       do {
00635        if (suffix[0] == '\0')
00636          {
00637            completer = find_completer (place, completer, suffix);
00638          }
00639        else
00640          {
00641            get_opc_prefix (&curr_suffix, op);
00642            completer = find_completer (place, completer, op);
00643          }
00644        if (completer != -1)
00645          {
00646            curr_insn = apply_completer (curr_insn, completer);
00647          }
00648       } while (completer != -1 && curr_suffix[0] != '\0');
00649 
00650       if (completer != -1 && curr_suffix[0] == '\0'
00651          && completer_table[completer].terminal_completer)
00652        {
00653           int depind = completer_table[completer].dependencies;
00654          return make_ia64_opcode (curr_insn, name, place, depind);
00655        }
00656       else
00657        {
00658          place++;
00659        }
00660     }
00661   return NULL;
00662 }
00663 
00664 /* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL
00665    if one does not exist.
00666 
00667    It is the caller's responsibility to invoke ia64_free_opcode () to
00668    release any resources used by the returned entry. */
00669 
00670 struct ia64_opcode *
00671 ia64_find_next_opcode (struct ia64_opcode *prev_ent)
00672 {
00673   return ia64_find_matching_opcode (prev_ent->name,
00674                                 prev_ent->ent_index + 1);
00675 }
00676 
00677 /* Find the first opcode that matches NAME, or return NULL if it does
00678    not exist.
00679 
00680    It is the caller's responsibility to invoke ia64_free_opcode () to
00681    release any resources used by the returned entry. */
00682 
00683 struct ia64_opcode *
00684 ia64_find_opcode (const char *name)
00685 {
00686   char op[129];
00687   const char *suffix;
00688   short place;
00689   short name_index;
00690 
00691   if (strlen (name) > 128)
00692     {
00693       return NULL;
00694     }
00695   suffix = name;
00696   get_opc_prefix (&suffix, op);
00697   name_index = find_string_ent (op);
00698   if (name_index < 0)
00699     {
00700       return NULL;
00701     }
00702 
00703   place = find_main_ent (name_index);
00704 
00705   if (place < 0)
00706     {
00707       return NULL;
00708     }
00709   return ia64_find_matching_opcode (name, place);
00710 }
00711 
00712 /* Free any resources used by ENT. */
00713 void
00714 ia64_free_opcode (struct ia64_opcode *ent)
00715 {
00716   free ((void *)ent->name);
00717   free (ent);
00718 }
00719 
00720 const struct ia64_dependency *
00721 ia64_find_dependency (int index)
00722 {
00723   index = DEP(index);
00724 
00725   if (index < 0
00726       || index >= (int)(sizeof(dependencies) / sizeof(dependencies[0])))
00727     return NULL;
00728 
00729   return &dependencies[index];
00730 }