(linenum→info "unix/slp.c:2238")

binutils/2.18/opcodes/cgen-asm.c

    1: /* CGEN generic assembler support code.
    2:    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2007
    3:    Free Software Foundation, Inc.
    4: 
    5:    This file is part of libopcodes.
    6: 
    7:    This library is free software; you can redistribute it and/or modify
    8:    it under the terms of the GNU General Public License as published by
    9:    the Free Software Foundation; either version 3, or (at your option)
   10:    any later version.
   11: 
   12:    It is distributed in the hope that it will be useful, but WITHOUT
   13:    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   14:    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   15:    License for more details.
   16: 
   17: 
   18:    You should have received a copy of the GNU General Public License along
   19:    with this program; if not, write to the Free Software Foundation, Inc.,
   20:    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
   21: 
   22: #include "sysdep.h"
   23: #include <stdio.h>
   24: #include "ansidecl.h"
   25: #include "libiberty.h"
   26: #include "safe-ctype.h"
   27: #include "bfd.h"
   28: #include "symcat.h"
   29: #include "opcode/cgen.h"
   30: #include "opintl.h"
   31: 
   32: static CGEN_INSN_LIST *  hash_insn_array      (CGEN_CPU_DESC, const CGEN_INSN *, int, int, CGEN_INSN_LIST **, CGEN_INSN_LIST *);
   33: static CGEN_INSN_LIST *  hash_insn_list       (CGEN_CPU_DESC, const CGEN_INSN_LIST *, CGEN_INSN_LIST **, CGEN_INSN_LIST *);
   34: static void              build_asm_hash_table (CGEN_CPU_DESC);
   35: 
   36: /* Set the cgen_parse_operand_fn callback.  */
   37: 
   38: void
   39: cgen_set_parse_operand_fn (CGEN_CPU_DESC cd, cgen_parse_operand_fn fn)
   40: {
   41:   cd->parse_operand_fn = fn;
   42: }
   43: 
   44: /* Called whenever starting to parse an insn.  */
   45: 
   46: void
   47: cgen_init_parse_operand (CGEN_CPU_DESC cd)
   48: {
   49:   /* This tells the callback to re-initialize.  */
   50:   (void) (* cd->parse_operand_fn)
   51:     (cd, CGEN_PARSE_OPERAND_INIT, NULL, 0, 0, NULL, NULL);
   52: }
   53: 
   54: /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
   55: 
   56:    COUNT is the number of elements in INSNS.
   57:    ENTSIZE is sizeof (CGEN_IBASE) for the target.
   58:    ??? No longer used but leave in for now.
   59:    HTABLE points to the hash table.
   60:    HENTBUF is a pointer to sufficiently large buffer of hash entries.
   61:    The result is a pointer to the next entry to use.
   62: 
   63:    The table is scanned backwards as additions are made to the front of the
   64:    list and we want earlier ones to be prefered.  */
   65: 
   66: static CGEN_INSN_LIST *
   67: hash_insn_array (CGEN_CPU_DESC cd,
   68:                  const CGEN_INSN *insns,
   69:                  int count,
   70:                  int entsize ATTRIBUTE_UNUSED,
   71:                  CGEN_INSN_LIST **htable,
   72:                  CGEN_INSN_LIST *hentbuf)
   73: {
   74:   int i;
   75: 
   76:   for (i = count - 1; i >= 0; --i, ++hentbuf)
   77:     {
   78:       unsigned int hash;
   79:       const CGEN_INSN *insn = &insns[i];
   80: 
   81:       if (! (* cd->asm_hash_p) (insn))
   82:         continue;
   83:       hash = (* cd->asm_hash) (CGEN_INSN_MNEMONIC (insn));
   84:       hentbuf->next = htable[hash];
   85:       hentbuf->insn = insn;
   86:       htable[hash] = hentbuf;
   87:     }
   88: 
   89:   return hentbuf;
   90: }
   91: 
   92: /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
   93:    This function is identical to hash_insn_array except the insns are
   94:    in a list.  */
   95: 
   96: static CGEN_INSN_LIST *
   97: hash_insn_list (CGEN_CPU_DESC cd,
   98:                 const CGEN_INSN_LIST *insns,
   99:                 CGEN_INSN_LIST **htable,
  100:                 CGEN_INSN_LIST *hentbuf)
  101: {
  102:   const CGEN_INSN_LIST *ilist;
  103: 
  104:   for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
  105:     {
  106:       unsigned int hash;
  107: 
  108:       if (! (* cd->asm_hash_p) (ilist->insn))
  109:         continue;
  110:       hash = (* cd->asm_hash) (CGEN_INSN_MNEMONIC (ilist->insn));
  111:       hentbuf->next = htable[hash];
  112:       hentbuf->insn = ilist->insn;
  113:       htable[hash] = hentbuf;
  114:     }
  115: 
  116:   return hentbuf;
  117: }
  118: 
  119: /* Build the assembler instruction hash table.  */
  120: 
  121: static void
  122: build_asm_hash_table (CGEN_CPU_DESC cd)
  123: {
  124:   int count = cgen_insn_count (cd) + cgen_macro_insn_count (cd);
  125:   CGEN_INSN_TABLE *insn_table = &cd->insn_table;
  126:   CGEN_INSN_TABLE *macro_insn_table = &cd->macro_insn_table;
  127:   unsigned int hash_size = cd->asm_hash_size;
  128:   CGEN_INSN_LIST *hash_entry_buf;
  129:   CGEN_INSN_LIST **asm_hash_table;
  130:   CGEN_INSN_LIST *asm_hash_table_entries;
  131: 
  132:   /* The space allocated for the hash table consists of two parts:
  133:      the hash table and the hash lists.  */
  134: 
  135:   asm_hash_table = (CGEN_INSN_LIST **)
  136:     xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
  137:   memset (asm_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
  138:   asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
  139:     xmalloc (count * sizeof (CGEN_INSN_LIST));
  140: 
  141:   /* Add compiled in insns.
  142:      Don't include the first one as it is a reserved entry.  */
  143:   /* ??? It was the end of all hash chains, and also the special
  144:      "invalid insn" marker.  May be able to do it differently now.  */
  145: 
  146:   hash_entry_buf = hash_insn_array (cd,
  147:                                     insn_table->init_entries + 1,
  148:                                     insn_table->num_init_entries - 1,
  149:                                     insn_table->entry_size,
  150:                                     asm_hash_table, hash_entry_buf);
  151: 
  152:   /* Add compiled in macro-insns.  */
  153: 
  154:   hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries,
  155:                                     macro_insn_table->num_init_entries,
  156:                                     macro_insn_table->entry_size,
  157:                                     asm_hash_table, hash_entry_buf);
  158: 
  159:   /* Add runtime added insns.
  160:      Later added insns will be prefered over earlier ones.  */
  161: 
  162:   hash_entry_buf = hash_insn_list (cd, insn_table->new_entries,
  163:                                    asm_hash_table, hash_entry_buf);
  164: 
  165:   /* Add runtime added macro-insns.  */
  166: 
  167:   hash_insn_list (cd, macro_insn_table->new_entries,
  168:                   asm_hash_table, hash_entry_buf);
  169: 
  170:   cd->asm_hash_table = asm_hash_table;
  171:   cd->asm_hash_table_entries = asm_hash_table_entries;
  172: }
  173: 
  174: /* Return the first entry in the hash list for INSN.  */
  175: 
  176: CGEN_INSN_LIST *
  177: cgen_asm_lookup_insn (CGEN_CPU_DESC cd, const char *insn)
  178: {
  179:   unsigned int hash;
  180: 
  181:   if (cd->asm_hash_table == NULL)
  182:     build_asm_hash_table (cd);
  183: 
  184:   hash = (* cd->asm_hash) (insn);
  185:   return cd->asm_hash_table[hash];
  186: }
  187: ^L
  188: /* Keyword parser.
  189:    The result is NULL upon success or an error message.
  190:    If successful, *STRP is updated to point passed the keyword.
  191: 
  192:    ??? At present we have a static notion of how to pick out a keyword.
  193:    Later we can allow a target to customize this if necessary [say by
  194:    recording something in the keyword table].  */
  195: 
  196: const char *
  197: cgen_parse_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  198:                     const char **strp,
  199:                     CGEN_KEYWORD *keyword_table,
  200:                     long *valuep)
  201: {
  202:   const CGEN_KEYWORD_ENTRY *ke;
  203:   char buf[256];
  204:   const char *p,*start;
  205: 
  206:   if (keyword_table->name_hash_table == NULL)
  207:     (void) cgen_keyword_search_init (keyword_table, NULL);
  208: 
  209:   p = start = *strp;
  210: 
  211:   /* Allow any first character.  This is to make life easier for
  212:      the fairly common case of suffixes, eg. 'ld.b.w', where the first
  213:      character of the suffix ('.') is special.  */
  214:   if (*p)
  215:     ++p;
  216:   
  217:   /* Allow letters, digits, and any special characters.  */
  218:   while (((p - start) < (int) sizeof (buf))
  219:          && *p
  220:          && (ISALNUM (*p)
  221:              || *p == '_'
  222:              || strchr (keyword_table->nonalpha_chars, *p)))
  223:     ++p;
  224: 
  225:   if (p - start >= (int) sizeof (buf))
  226:     {
  227:       /* All non-empty CGEN keywords can fit into BUF.  The only thing
  228:          we can match here is the empty keyword.  */
  229:       buf[0] = 0;
  230:     }
  231:   else
  232:     {
  233:       memcpy (buf, start, p - start);
  234:       buf[p - start] = 0;
  235:     }
  236: 
  237:   ke = cgen_keyword_lookup_name (keyword_table, buf);
  238: 
  239:   if (ke != NULL)
  240:     {
  241:       *valuep = ke->value;
  242:       /* Don't advance pointer if we recognized the null keyword.  */
  243:       if (ke->name[0] != 0)
  244:         *strp = p;
  245:       return NULL;
  246:     }
  247: 
  248:   return "unrecognized keyword/register name";
  249: }
  250: 
  251: /* Parse a small signed integer parser.
  252:    ??? VALUEP is not a bfd_vma * on purpose, though this is confusing.
  253:    Note that if the caller expects a bfd_vma result, it should call
  254:    cgen_parse_address.  */
  255: 
  256: const char *
  257: cgen_parse_signed_integer (CGEN_CPU_DESC cd,
  258:                            const char **strp,
  259:                            int opindex,
  260:                            long *valuep)
  261: {
  262:   bfd_vma value;
  263:   enum cgen_parse_operand_result result;
  264:   const char *errmsg;
  265: 
  266:   errmsg = (* cd->parse_operand_fn)
  267:     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
  268:      &result, &value);
  269:   /* FIXME: Examine `result'.  */
  270:   if (!errmsg)
  271:     *valuep = value;
  272:   return errmsg;
  273: }
  274: 
  275: /* Parse a small unsigned integer parser.
  276:    ??? VALUEP is not a bfd_vma * on purpose, though this is confusing.
  277:    Note that if the caller expects a bfd_vma result, it should call
  278:    cgen_parse_address.  */
  279: 
  280: const char *
  281: cgen_parse_unsigned_integer (CGEN_CPU_DESC cd,
  282:                              const char **strp,
  283:                              int opindex,
  284:                              unsigned long *valuep)
  285: {
  286:   bfd_vma value;
  287:   enum cgen_parse_operand_result result;
  288:   const char *errmsg;
  289: 
  290:   errmsg = (* cd->parse_operand_fn)
  291:     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
  292:      &result, &value);
  293:   /* FIXME: Examine `result'.  */
  294:   if (!errmsg)
  295:     *valuep = value;
  296:   return errmsg;
  297: }
  298: 
  299: /* Address parser.  */
  300: 
  301: const char *
  302: cgen_parse_address (CGEN_CPU_DESC cd,
  303:                     const char **strp,
  304:                     int opindex,
  305:                     int opinfo,
  306:                     enum cgen_parse_operand_result *resultp,
  307:                     bfd_vma *valuep)
  308: {
  309:   bfd_vma value;
  310:   enum cgen_parse_operand_result result_type;
  311:   const char *errmsg;
  312: 
  313:   errmsg = (* cd->parse_operand_fn)
  314:     (cd, CGEN_PARSE_OPERAND_ADDRESS, strp, opindex, opinfo,
  315:      &result_type, &value);
  316:   /* FIXME: Examine `result'.  */
  317:   if (!errmsg)
  318:     {
  319:       if (resultp != NULL)
  320:         *resultp = result_type;
  321:       *valuep = value;
  322:     }
  323:   return errmsg;
  324: }
  325: ^L
  326: /* Signed integer validation routine.  */
  327: 
  328: const char *
  329: cgen_validate_signed_integer (long value, long min, long max)
  330: {
  331:   if (value < min || value > max)
  332:     {
  333:       static char buf[100];
  334: 
  335:       /* xgettext:c-format */
  336:       sprintf (buf, _("operand out of range (%ld not between %ld and %ld)"),
  337:                       value, min, max);
  338:       return buf;
  339:     }
  340: 
  341:   return NULL;
  342: }
  343: 
  344: /* Unsigned integer validation routine.
  345:    Supplying `min' here may seem unnecessary, but we also want to handle
  346:    cases where min != 0 (and max > LONG_MAX).  */
  347: 
  348: const char *
  349: cgen_validate_unsigned_integer (unsigned long value,
  350:                                 unsigned long min,
  351:                                 unsigned long max)
  352: {
  353:   if (value < min || value > max)
  354:     {
  355:       static char buf[100];
  356: 
  357:       /* xgettext:c-format */
  358:       sprintf (buf, _("operand out of range (%lu not between %lu and %lu)"),
  359:                value, min, max);
  360:       return buf;
  361:     }
  362: 
  363:   return NULL;
  364: }
Syntax (Markdown)