~ubuntu-branches/ubuntu/utopic/binutils-arm64-cross/utopic

« back to all changes in this revision

Viewing changes to binutils-2.23.52.20130611/opcodes/cgen-asm.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-06-20 17:38:09 UTC
  • Revision ID: package-import@ubuntu.com-20130620173809-app8lzgvymy5fg6c
Tags: 0.7
Build-depend on binutils-source (>= 2.23.52.20130620-1~).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* CGEN generic assembler support code.
 
2
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007,
 
3
   2011  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
 
 
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
    {
 
272
      /* Handle the case where a hex value is parsed on a 64-bit host.
 
273
         A value like 0xffffe000 is clearly intended to be a negative
 
274
         16-bit value, but on a 64-bit host it will be parsed by gas
 
275
         as 0x00000000ffffe000.
 
276
 
 
277
         The shifts below are designed not to produce compile time
 
278
         warnings on a 32-bit host.  */
 
279
      if (sizeof (value) > 4
 
280
          && result == CGEN_PARSE_OPERAND_RESULT_NUMBER
 
281
          && value > 0
 
282
          && (value & 0x80000000)
 
283
          && ((value >> 31) == 1))
 
284
        value |= -1 << 31;
 
285
 
 
286
      *valuep = value;
 
287
    }
 
288
  return errmsg;
 
289
}
 
290
 
 
291
/* Parse a small unsigned integer parser.
 
292
   ??? VALUEP is not a bfd_vma * on purpose, though this is confusing.
 
293
   Note that if the caller expects a bfd_vma result, it should call
 
294
   cgen_parse_address.  */
 
295
 
 
296
const char *
 
297
cgen_parse_unsigned_integer (CGEN_CPU_DESC cd,
 
298
                             const char **strp,
 
299
                             int opindex,
 
300
                             unsigned long *valuep)
 
301
{
 
302
  bfd_vma value;
 
303
  enum cgen_parse_operand_result result;
 
304
  const char *errmsg;
 
305
 
 
306
  errmsg = (* cd->parse_operand_fn)
 
307
    (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
 
308
     &result, &value);
 
309
  /* FIXME: Examine `result'.  */
 
310
  if (!errmsg)
 
311
    *valuep = value;
 
312
  return errmsg;
 
313
}
 
314
 
 
315
/* Address parser.  */
 
316
 
 
317
const char *
 
318
cgen_parse_address (CGEN_CPU_DESC cd,
 
319
                    const char **strp,
 
320
                    int opindex,
 
321
                    int opinfo,
 
322
                    enum cgen_parse_operand_result *resultp,
 
323
                    bfd_vma *valuep)
 
324
{
 
325
  bfd_vma value;
 
326
  enum cgen_parse_operand_result result_type;
 
327
  const char *errmsg;
 
328
 
 
329
  errmsg = (* cd->parse_operand_fn)
 
330
    (cd, CGEN_PARSE_OPERAND_ADDRESS, strp, opindex, opinfo,
 
331
     &result_type, &value);
 
332
  /* FIXME: Examine `result'.  */
 
333
  if (!errmsg)
 
334
    {
 
335
      if (resultp != NULL)
 
336
        *resultp = result_type;
 
337
      *valuep = value;
 
338
    }
 
339
  return errmsg;
 
340
}
 
341
 
 
342
/* Signed integer validation routine.  */
 
343
 
 
344
const char *
 
345
cgen_validate_signed_integer (long value, long min, long max)
 
346
{
 
347
  if (value < min || value > max)
 
348
    {
 
349
      static char buf[100];
 
350
 
 
351
      /* xgettext:c-format */
 
352
      sprintf (buf, _("operand out of range (%ld not between %ld and %ld)"),
 
353
                      value, min, max);
 
354
      return buf;
 
355
    }
 
356
 
 
357
  return NULL;
 
358
}
 
359
 
 
360
/* Unsigned integer validation routine.
 
361
   Supplying `min' here may seem unnecessary, but we also want to handle
 
362
   cases where min != 0 (and max > LONG_MAX).  */
 
363
 
 
364
const char *
 
365
cgen_validate_unsigned_integer (unsigned long value,
 
366
                                unsigned long min,
 
367
                                unsigned long max)
 
368
{
 
369
  if (value < min || value > max)
 
370
    {
 
371
      static char buf[100];
 
372
 
 
373
      /* xgettext:c-format */
 
374
      sprintf (buf, _("operand out of range (%lu not between %lu and %lu)"),
 
375
               value, min, max);
 
376
      return buf;
 
377
    }
 
378
 
 
379
  return NULL;
 
380
}