[BACK]Return to cgen-dis.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / gpl3 / binutils.old / dist / opcodes

Annotation of src/external/gpl3/binutils.old/dist/opcodes/cgen-dis.c, Revision 1.6

1.1       christos    1: /* CGEN generic disassembler support code.
1.6     ! christos    2:    Copyright (C) 1996-2018 Free Software Foundation, Inc.
1.1       christos    3:
                      4:    This file is part of libopcodes.
                      5:
                      6:    This library is free software; you can redistribute it and/or modify
                      7:    it under the terms of the GNU General Public License as published by
                      8:    the Free Software Foundation; either version 3, or (at your option)
                      9:    any later version.
                     10:
                     11:    It is distributed in the hope that it will be useful, but WITHOUT
                     12:    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
                     14:    License for more details.
                     15:
                     16:    You should have received a copy of the GNU General Public License along
                     17:    with this program; if not, write to the Free Software Foundation, Inc.,
                     18:    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
                     19:
                     20: #include "sysdep.h"
                     21: #include <stdio.h>
                     22: #include "ansidecl.h"
                     23: #include "libiberty.h"
                     24: #include "bfd.h"
                     25: #include "symcat.h"
                     26: #include "opcode/cgen.h"
                     27:
                     28: static CGEN_INSN_LIST *  hash_insn_array        (CGEN_CPU_DESC, const CGEN_INSN *, int, int, CGEN_INSN_LIST **, CGEN_INSN_LIST *);
                     29: static CGEN_INSN_LIST *  hash_insn_list         (CGEN_CPU_DESC, const CGEN_INSN_LIST *, CGEN_INSN_LIST **, CGEN_INSN_LIST *);
                     30: static void              build_dis_hash_table   (CGEN_CPU_DESC);
                     31: static int              count_decodable_bits   (const CGEN_INSN *);
                     32: static void             add_insn_to_hash_chain (CGEN_INSN_LIST *,
                     33:                                                 const CGEN_INSN *,
                     34:                                                 CGEN_INSN_LIST **,
                     35:                                                 unsigned int);
                     36:
                     37: /* Return the number of decodable bits in this insn.  */
                     38: static int
                     39: count_decodable_bits (const CGEN_INSN *insn)
                     40: {
                     41:   unsigned mask = CGEN_INSN_BASE_MASK (insn);
                     42:   int bits = 0;
1.5       christos   43:   unsigned m;
                     44:
1.1       christos   45:   for (m = 1; m != 0; m <<= 1)
                     46:     {
                     47:       if (mask & m)
                     48:        ++bits;
                     49:     }
                     50:   return bits;
                     51: }
                     52:
1.3       christos   53: /* Add an instruction to the hash chain.  */
1.1       christos   54: static void
                     55: add_insn_to_hash_chain (CGEN_INSN_LIST *hentbuf,
                     56:                        const CGEN_INSN *insn,
                     57:                        CGEN_INSN_LIST **htable,
                     58:                        unsigned int hash)
                     59: {
                     60:   CGEN_INSN_LIST *current_buf;
                     61:   CGEN_INSN_LIST *previous_buf;
                     62:   int insn_decodable_bits;
                     63:
                     64:   /* Add insns sorted by the number of decodable bits, in decreasing order.
                     65:      This ensures that any insn which is a special case of another will be
                     66:      checked first.  */
                     67:   insn_decodable_bits = count_decodable_bits (insn);
                     68:   previous_buf = NULL;
                     69:   for (current_buf = htable[hash]; current_buf != NULL;
                     70:        current_buf = current_buf->next)
                     71:     {
                     72:       int current_decodable_bits = count_decodable_bits (current_buf->insn);
                     73:       if (insn_decodable_bits >= current_decodable_bits)
                     74:        break;
                     75:       previous_buf = current_buf;
                     76:     }
                     77:
                     78:   /* Now insert the new insn.  */
                     79:   hentbuf->insn = insn;
                     80:   hentbuf->next = current_buf;
                     81:   if (previous_buf == NULL)
                     82:     htable[hash] = hentbuf;
                     83:   else
                     84:     previous_buf->next = hentbuf;
                     85: }
                     86:
                     87: /* Subroutine of build_dis_hash_table to add INSNS to the hash table.
                     88:
                     89:    COUNT is the number of elements in INSNS.
                     90:    ENTSIZE is sizeof (CGEN_IBASE) for the target.
                     91:    ??? No longer used but leave in for now.
                     92:    HTABLE points to the hash table.
                     93:    HENTBUF is a pointer to sufficiently large buffer of hash entries.
                     94:    The result is a pointer to the next entry to use.
                     95:
                     96:    The table is scanned backwards as additions are made to the front of the
                     97:    list and we want earlier ones to be prefered.  */
                     98:
                     99: static CGEN_INSN_LIST *
                    100: hash_insn_array (CGEN_CPU_DESC cd,
                    101:                 const CGEN_INSN * insns,
                    102:                 int count,
                    103:                 int entsize ATTRIBUTE_UNUSED,
                    104:                 CGEN_INSN_LIST ** htable,
                    105:                 CGEN_INSN_LIST * hentbuf)
                    106: {
1.3       christos  107:   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
1.1       christos  108:   int i;
                    109:
                    110:   for (i = count - 1; i >= 0; --i, ++hentbuf)
                    111:     {
                    112:       unsigned int hash;
                    113:       char buf [4];
                    114:       unsigned long value;
                    115:       const CGEN_INSN *insn = &insns[i];
                    116:
                    117:       if (! (* cd->dis_hash_p) (insn))
                    118:        continue;
                    119:
                    120:       /* We don't know whether the target uses the buffer or the base insn
                    121:         to hash on, so set both up.  */
                    122:
                    123:       value = CGEN_INSN_BASE_VALUE (insn);
                    124:       bfd_put_bits ((bfd_vma) value,
                    125:                    buf,
                    126:                    CGEN_INSN_MASK_BITSIZE (insn),
                    127:                    big_p);
                    128:       hash = (* cd->dis_hash) (buf, value);
                    129:       add_insn_to_hash_chain (hentbuf, insn, htable, hash);
                    130:     }
                    131:
                    132:   return hentbuf;
                    133: }
                    134:
                    135: /* Subroutine of build_dis_hash_table to add INSNS to the hash table.
                    136:    This function is identical to hash_insn_array except the insns are
                    137:    in a list.  */
                    138:
                    139: static CGEN_INSN_LIST *
                    140: hash_insn_list (CGEN_CPU_DESC cd,
                    141:                const CGEN_INSN_LIST *insns,
                    142:                CGEN_INSN_LIST **htable,
                    143:                CGEN_INSN_LIST *hentbuf)
                    144: {
1.3       christos  145:   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
1.1       christos  146:   const CGEN_INSN_LIST *ilist;
                    147:
                    148:   for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
                    149:     {
                    150:       unsigned int hash;
                    151:       char buf[4];
                    152:       unsigned long value;
                    153:
                    154:       if (! (* cd->dis_hash_p) (ilist->insn))
                    155:        continue;
                    156:
                    157:       /* We don't know whether the target uses the buffer or the base insn
                    158:         to hash on, so set both up.  */
                    159:
                    160:       value = CGEN_INSN_BASE_VALUE (ilist->insn);
                    161:       bfd_put_bits((bfd_vma) value,
                    162:                   buf,
                    163:                   CGEN_INSN_MASK_BITSIZE (ilist->insn),
                    164:                   big_p);
                    165:       hash = (* cd->dis_hash) (buf, value);
                    166:       add_insn_to_hash_chain (hentbuf, ilist->insn, htable, hash);
                    167:     }
                    168:
                    169:   return hentbuf;
                    170: }
                    171:
                    172: /* Build the disassembler instruction hash table.  */
                    173:
                    174: static void
                    175: build_dis_hash_table (CGEN_CPU_DESC cd)
                    176: {
                    177:   int count = cgen_insn_count (cd) + cgen_macro_insn_count (cd);
                    178:   CGEN_INSN_TABLE *insn_table = & cd->insn_table;
                    179:   CGEN_INSN_TABLE *macro_insn_table = & cd->macro_insn_table;
                    180:   unsigned int hash_size = cd->dis_hash_size;
                    181:   CGEN_INSN_LIST *hash_entry_buf;
                    182:   CGEN_INSN_LIST **dis_hash_table;
                    183:   CGEN_INSN_LIST *dis_hash_table_entries;
                    184:
                    185:   /* The space allocated for the hash table consists of two parts:
                    186:      the hash table and the hash lists.  */
                    187:
                    188:   dis_hash_table = (CGEN_INSN_LIST **)
                    189:     xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
                    190:   memset (dis_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
                    191:   dis_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
                    192:     xmalloc (count * sizeof (CGEN_INSN_LIST));
                    193:
                    194:   /* Add compiled in insns.
                    195:      Don't include the first one as it is a reserved entry.  */
                    196:   /* ??? It was the end of all hash chains, and also the special
                    197:      "invalid insn" marker.  May be able to do it differently now.  */
                    198:
                    199:   hash_entry_buf = hash_insn_array (cd,
                    200:                                    insn_table->init_entries + 1,
                    201:                                    insn_table->num_init_entries - 1,
                    202:                                    insn_table->entry_size,
                    203:                                    dis_hash_table, hash_entry_buf);
                    204:
                    205:   /* Add compiled in macro-insns.  */
                    206:
                    207:   hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries,
                    208:                                    macro_insn_table->num_init_entries,
                    209:                                    macro_insn_table->entry_size,
                    210:                                    dis_hash_table, hash_entry_buf);
                    211:
                    212:   /* Add runtime added insns.
                    213:      Later added insns will be prefered over earlier ones.  */
                    214:
                    215:   hash_entry_buf = hash_insn_list (cd, insn_table->new_entries,
                    216:                                   dis_hash_table, hash_entry_buf);
                    217:
                    218:   /* Add runtime added macro-insns.  */
                    219:
                    220:   hash_insn_list (cd, macro_insn_table->new_entries,
                    221:                  dis_hash_table, hash_entry_buf);
                    222:
                    223:   cd->dis_hash_table = dis_hash_table;
                    224:   cd->dis_hash_table_entries = dis_hash_table_entries;
                    225: }
                    226:
                    227: /* Return the first entry in the hash list for INSN.  */
                    228:
                    229: CGEN_INSN_LIST *
                    230: cgen_dis_lookup_insn (CGEN_CPU_DESC cd, const char * buf, CGEN_INSN_INT value)
                    231: {
                    232:   unsigned int hash;
                    233:
                    234:   if (cd->dis_hash_table == NULL)
                    235:     build_dis_hash_table (cd);
                    236:
                    237:   hash = (* cd->dis_hash) (buf, value);
                    238:
                    239:   return cd->dis_hash_table[hash];
                    240: }

CVSweb <webmaster@jp.NetBSD.org>