]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/cgen-opc.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / opcodes / cgen-opc.c
1 /* CGEN generic opcode support.
2
3 Copyright (C) 1996-2023 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 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
20
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include "ansidecl.h"
24 #include "libiberty.h"
25 #include "safe-ctype.h"
26 #include "bfd.h"
27 #include "symcat.h"
28 #include "opcode/cgen.h"
29
30 static unsigned int hash_keyword_name
31 (const CGEN_KEYWORD *, const char *, int);
32 static unsigned int hash_keyword_value
33 (const CGEN_KEYWORD *, unsigned int);
34 static void build_keyword_hash_tables
35 (CGEN_KEYWORD *);
36
37 /* Return number of hash table entries to use for N elements. */
38 #define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
39
40 /* Look up *NAMEP in the keyword table KT.
41 The result is the keyword entry or NULL if not found. */
42
43 const CGEN_KEYWORD_ENTRY *
44 cgen_keyword_lookup_name (CGEN_KEYWORD *kt, const char *name)
45 {
46 const CGEN_KEYWORD_ENTRY *ke;
47 const char *p,*n;
48
49 if (kt->name_hash_table == NULL)
50 build_keyword_hash_tables (kt);
51
52 ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
53
54 /* We do case insensitive comparisons.
55 If that ever becomes a problem, add an attribute that denotes
56 "do case sensitive comparisons". */
57
58 while (ke != NULL)
59 {
60 n = name;
61 p = ke->name;
62
63 while (*p
64 && (*p == *n
65 || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n)))))
66 ++n, ++p;
67
68 if (!*p && !*n)
69 return ke;
70
71 ke = ke->next_name;
72 }
73
74 if (kt->null_entry)
75 return kt->null_entry;
76 return NULL;
77 }
78
79 /* Look up VALUE in the keyword table KT.
80 The result is the keyword entry or NULL if not found. */
81
82 const CGEN_KEYWORD_ENTRY *
83 cgen_keyword_lookup_value (CGEN_KEYWORD *kt, int value)
84 {
85 const CGEN_KEYWORD_ENTRY *ke;
86
87 if (kt->name_hash_table == NULL)
88 build_keyword_hash_tables (kt);
89
90 ke = kt->value_hash_table[hash_keyword_value (kt, value)];
91
92 while (ke != NULL)
93 {
94 if (value == ke->value)
95 return ke;
96 ke = ke->next_value;
97 }
98
99 return NULL;
100 }
101
102 /* Add an entry to a keyword table. */
103
104 void
105 cgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke)
106 {
107 unsigned int hash;
108 size_t i;
109
110 if (kt->name_hash_table == NULL)
111 build_keyword_hash_tables (kt);
112
113 hash = hash_keyword_name (kt, ke->name, 0);
114 ke->next_name = kt->name_hash_table[hash];
115 kt->name_hash_table[hash] = ke;
116
117 hash = hash_keyword_value (kt, ke->value);
118 ke->next_value = kt->value_hash_table[hash];
119 kt->value_hash_table[hash] = ke;
120
121 if (ke->name[0] == 0)
122 kt->null_entry = ke;
123
124 for (i = 1; i < strlen (ke->name); i++)
125 if (! ISALNUM (ke->name[i])
126 && ! strchr (kt->nonalpha_chars, ke->name[i]))
127 {
128 size_t idx = strlen (kt->nonalpha_chars);
129
130 /* If you hit this limit, please don't just
131 increase the size of the field, instead
132 look for a better algorithm. */
133 if (idx >= sizeof (kt->nonalpha_chars) - 1)
134 abort ();
135 kt->nonalpha_chars[idx] = ke->name[i];
136 kt->nonalpha_chars[idx+1] = 0;
137 }
138 }
139
140 /* FIXME: Need function to return count of keywords. */
141
142 /* Initialize a keyword table search.
143 SPEC is a specification of what to search for.
144 A value of NULL means to find every keyword.
145 Currently NULL is the only acceptable value [further specification
146 deferred].
147 The result is an opaque data item used to record the search status.
148 It is passed to each call to cgen_keyword_search_next. */
149
150 CGEN_KEYWORD_SEARCH
151 cgen_keyword_search_init (CGEN_KEYWORD *kt, const char *spec)
152 {
153 CGEN_KEYWORD_SEARCH search;
154
155 /* FIXME: Need to specify format of params. */
156 if (spec != NULL)
157 abort ();
158
159 if (kt->name_hash_table == NULL)
160 build_keyword_hash_tables (kt);
161
162 search.table = kt;
163 search.spec = spec;
164 search.current_hash = 0;
165 search.current_entry = NULL;
166 return search;
167 }
168
169 /* Return the next keyword specified by SEARCH.
170 The result is the next entry or NULL if there are no more. */
171
172 const CGEN_KEYWORD_ENTRY *
173 cgen_keyword_search_next (CGEN_KEYWORD_SEARCH *search)
174 {
175 /* Has search finished? */
176 if (search->current_hash == search->table->hash_table_size)
177 return NULL;
178
179 /* Search in progress? */
180 if (search->current_entry != NULL
181 /* Anything left on this hash chain? */
182 && search->current_entry->next_name != NULL)
183 {
184 search->current_entry = search->current_entry->next_name;
185 return search->current_entry;
186 }
187
188 /* Move to next hash chain [unless we haven't started yet]. */
189 if (search->current_entry != NULL)
190 ++search->current_hash;
191
192 while (search->current_hash < search->table->hash_table_size)
193 {
194 search->current_entry = search->table->name_hash_table[search->current_hash];
195 if (search->current_entry != NULL)
196 return search->current_entry;
197 ++search->current_hash;
198 }
199
200 return NULL;
201 }
202
203 /* Return first entry in hash chain for NAME.
204 If CASE_SENSITIVE_P is non-zero, return a case sensitive hash. */
205
206 static unsigned int
207 hash_keyword_name (const CGEN_KEYWORD *kt,
208 const char *name,
209 int case_sensitive_p)
210 {
211 unsigned int hash;
212
213 if (case_sensitive_p)
214 for (hash = 0; *name; ++name)
215 hash = (hash * 97) + (unsigned char) *name;
216 else
217 for (hash = 0; *name; ++name)
218 hash = (hash * 97) + (unsigned char) TOLOWER (*name);
219 return hash % kt->hash_table_size;
220 }
221
222 /* Return first entry in hash chain for VALUE. */
223
224 static unsigned int
225 hash_keyword_value (const CGEN_KEYWORD *kt, unsigned int value)
226 {
227 return value % kt->hash_table_size;
228 }
229
230 /* Build a keyword table's hash tables.
231 We probably needn't build the value hash table for the assembler when
232 we're using the disassembler, but we keep things simple. */
233
234 static void
235 build_keyword_hash_tables (CGEN_KEYWORD *kt)
236 {
237 int i;
238 /* Use the number of compiled in entries as an estimate for the
239 typical sized table [not too many added at runtime]. */
240 unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
241
242 kt->hash_table_size = size;
243 kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
244 xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
245 memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
246 kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
247 xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
248 memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
249
250 /* The table is scanned backwards as we want keywords appearing earlier to
251 be prefered over later ones. */
252 for (i = kt->num_init_entries - 1; i >= 0; --i)
253 cgen_keyword_add (kt, &kt->init_entries[i]);
254 }
255 \f
256 /* Hardware support. */
257
258 /* Lookup a hardware element by its name.
259 Returns NULL if NAME is not supported by the currently selected
260 mach/isa. */
261
262 const CGEN_HW_ENTRY *
263 cgen_hw_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
264 {
265 unsigned int i;
266 const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
267
268 for (i = 0; i < cd->hw_table.num_entries; ++i)
269 if (hw[i] && strcmp (name, hw[i]->name) == 0)
270 return hw[i];
271
272 return NULL;
273 }
274
275 /* Lookup a hardware element by its number.
276 Hardware elements are enumerated, however it may be possible to add some
277 at runtime, thus HWNUM is not an enum type but rather an int.
278 Returns NULL if HWNUM is not supported by the currently selected mach. */
279
280 const CGEN_HW_ENTRY *
281 cgen_hw_lookup_by_num (CGEN_CPU_DESC cd, unsigned int hwnum)
282 {
283 unsigned int i;
284 const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
285
286 /* ??? This can be speeded up. */
287 for (i = 0; i < cd->hw_table.num_entries; ++i)
288 if (hw[i] && hwnum == hw[i]->type)
289 return hw[i];
290
291 return NULL;
292 }
293 \f
294 /* Operand support. */
295
296 /* Lookup an operand by its name.
297 Returns NULL if NAME is not supported by the currently selected
298 mach/isa. */
299
300 const CGEN_OPERAND *
301 cgen_operand_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
302 {
303 unsigned int i;
304 const CGEN_OPERAND **op = cd->operand_table.entries;
305
306 for (i = 0; i < cd->operand_table.num_entries; ++i)
307 if (op[i] && strcmp (name, op[i]->name) == 0)
308 return op[i];
309
310 return NULL;
311 }
312
313 /* Lookup an operand by its number.
314 Operands are enumerated, however it may be possible to add some
315 at runtime, thus OPNUM is not an enum type but rather an int.
316 Returns NULL if OPNUM is not supported by the currently selected
317 mach/isa. */
318
319 const CGEN_OPERAND *
320 cgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum)
321 {
322 return cd->operand_table.entries[opnum];
323 }
324 \f
325 /* Instruction support. */
326
327 /* Return number of instructions. This includes any added at runtime. */
328
329 int
330 cgen_insn_count (CGEN_CPU_DESC cd)
331 {
332 int count = cd->insn_table.num_init_entries;
333 CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
334
335 for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
336 ++count;
337
338 return count;
339 }
340
341 /* Return number of macro-instructions.
342 This includes any added at runtime. */
343
344 int
345 cgen_macro_insn_count (CGEN_CPU_DESC cd)
346 {
347 int count = cd->macro_insn_table.num_init_entries;
348 CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
349
350 for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
351 ++count;
352
353 return count;
354 }
355
356 /* Cover function to read and properly byteswap an insn value. */
357
358 CGEN_INSN_INT
359 cgen_get_insn_value (CGEN_CPU_DESC cd, unsigned char *buf, int length,
360 int endian)
361 {
362 int big_p = (endian == CGEN_ENDIAN_BIG);
363 int insn_chunk_bitsize = cd->insn_chunk_bitsize;
364 CGEN_INSN_INT value = 0;
365
366 if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
367 {
368 /* We need to divide up the incoming value into insn_chunk_bitsize-length
369 segments, and endian-convert them, one at a time. */
370 int i;
371
372 /* Enforce divisibility. */
373 if ((length % insn_chunk_bitsize) != 0)
374 abort ();
375
376 for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
377 {
378 int bit_index;
379 bfd_vma this_value;
380
381 bit_index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
382 this_value = bfd_get_bits (& buf[bit_index / 8], insn_chunk_bitsize, big_p);
383 value = (value << insn_chunk_bitsize) | this_value;
384 }
385 }
386 else
387 {
388 value = bfd_get_bits (buf, length, endian == CGEN_ENDIAN_BIG);
389 }
390
391 return value;
392 }
393
394 /* Cover function to store an insn value properly byteswapped. */
395
396 void
397 cgen_put_insn_value (CGEN_CPU_DESC cd,
398 unsigned char *buf,
399 int length,
400 CGEN_INSN_INT value,
401 int endian)
402 {
403 int big_p = (endian == CGEN_ENDIAN_BIG);
404 int insn_chunk_bitsize = cd->insn_chunk_bitsize;
405
406 if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
407 {
408 /* We need to divide up the incoming value into insn_chunk_bitsize-length
409 segments, and endian-convert them, one at a time. */
410 int i;
411
412 /* Enforce divisibility. */
413 if ((length % insn_chunk_bitsize) != 0)
414 abort ();
415
416 for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
417 {
418 int bit_index;
419
420 bit_index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
421 bfd_put_bits ((bfd_vma) value, & buf[bit_index / 8], insn_chunk_bitsize, big_p);
422 value >>= insn_chunk_bitsize;
423 }
424 }
425 else
426 {
427 bfd_put_bits ((bfd_vma) value, buf, length, big_p);
428 }
429 }
430 \f
431 /* Look up instruction INSN_*_VALUE and extract its fields.
432 INSN_INT_VALUE is used if CGEN_INT_INSN_P.
433 Otherwise INSN_BYTES_VALUE is used.
434 INSN, if non-null, is the insn table entry.
435 Otherwise INSN_*_VALUE is examined to compute it.
436 LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
437 0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
438 If INSN != NULL, LENGTH must be valid.
439 ALIAS_P is non-zero if alias insns are to be included in the search.
440
441 The result is a pointer to the insn table entry, or NULL if the instruction
442 wasn't recognized. */
443
444 /* ??? Will need to be revisited for VLIW architectures. */
445
446 const CGEN_INSN *
447 cgen_lookup_insn (CGEN_CPU_DESC cd,
448 const CGEN_INSN *insn,
449 CGEN_INSN_INT insn_int_value,
450 /* ??? CGEN_INSN_BYTES would be a nice type name to use here. */
451 unsigned char *insn_bytes_value,
452 int length,
453 CGEN_FIELDS *fields,
454 int alias_p)
455 {
456 CGEN_EXTRACT_INFO ex_info;
457 CGEN_EXTRACT_INFO *info;
458
459 if (cd->int_insn_p)
460 {
461 info = NULL;
462 insn_bytes_value = (unsigned char *) xmalloc (cd->max_insn_bitsize / 8);
463 cgen_put_insn_value (cd, insn_bytes_value, length, insn_int_value,
464 cd->insn_endian);
465 }
466 else
467 {
468 info = &ex_info;
469 ex_info.dis_info = NULL;
470 ex_info.insn_bytes = insn_bytes_value;
471 ex_info.valid = -1;
472 insn_int_value = cgen_get_insn_value (cd, insn_bytes_value, length,
473 cd->insn_endian);
474 }
475
476 if (!insn)
477 {
478 const CGEN_INSN_LIST *insn_list;
479
480 /* The instructions are stored in hash lists.
481 Pick the first one and keep trying until we find the right one. */
482
483 insn_list = cgen_dis_lookup_insn (cd, (char *) insn_bytes_value,
484 insn_int_value);
485 while (insn_list != NULL)
486 {
487 insn = insn_list->insn;
488
489 if (alias_p
490 /* FIXME: Ensure ALIAS attribute always has same index. */
491 || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
492 {
493 /* Basic bit mask must be correct. */
494 /* ??? May wish to allow target to defer this check until the
495 extract handler. */
496 if ((insn_int_value & CGEN_INSN_BASE_MASK (insn))
497 == CGEN_INSN_BASE_VALUE (insn))
498 {
499 /* ??? 0 is passed for `pc' */
500 int elength = CGEN_EXTRACT_FN (cd, insn)
501 (cd, insn, info, insn_int_value, fields, (bfd_vma) 0);
502 if (elength > 0)
503 {
504 /* sanity check */
505 if (length != 0 && length != elength)
506 abort ();
507 break;
508 }
509 }
510 }
511
512 insn_list = insn_list->next;
513 }
514 }
515 else
516 {
517 /* Sanity check: can't pass an alias insn if ! alias_p. */
518 if (! alias_p
519 && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
520 abort ();
521 /* Sanity check: length must be correct. */
522 if (length != CGEN_INSN_BITSIZE (insn))
523 abort ();
524
525 /* ??? 0 is passed for `pc' */
526 length = CGEN_EXTRACT_FN (cd, insn)
527 (cd, insn, info, insn_int_value, fields, (bfd_vma) 0);
528 /* Sanity check: must succeed.
529 Could relax this later if it ever proves useful. */
530 if (length == 0)
531 abort ();
532 }
533
534 if (cd->int_insn_p)
535 free (insn_bytes_value);
536
537 return insn;
538 }
539
540 /* Fill in the operand instances used by INSN whose operands are FIELDS.
541 INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
542 in. */
543
544 void
545 cgen_get_insn_operands (CGEN_CPU_DESC cd,
546 const CGEN_INSN *insn,
547 const CGEN_FIELDS *fields,
548 int *indices)
549 {
550 const CGEN_OPINST *opinst;
551 int i;
552
553 if (insn->opinst == NULL)
554 abort ();
555 for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
556 {
557 enum cgen_operand_type op_type = opinst->op_type;
558 if (op_type == CGEN_OPERAND_NIL)
559 indices[i] = opinst->index;
560 else
561 indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
562 }
563 }
564
565 /* Cover function to cgen_get_insn_operands when either INSN or FIELDS
566 isn't known.
567 The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
568 cgen_lookup_insn unchanged.
569 INSN_INT_VALUE is used if CGEN_INT_INSN_P.
570 Otherwise INSN_BYTES_VALUE is used.
571
572 The result is the insn table entry or NULL if the instruction wasn't
573 recognized. */
574
575 const CGEN_INSN *
576 cgen_lookup_get_insn_operands (CGEN_CPU_DESC cd,
577 const CGEN_INSN *insn,
578 CGEN_INSN_INT insn_int_value,
579 /* ??? CGEN_INSN_BYTES would be a nice type name to use here. */
580 unsigned char *insn_bytes_value,
581 int length,
582 int *indices,
583 CGEN_FIELDS *fields)
584 {
585 /* Pass non-zero for ALIAS_P only if INSN != NULL.
586 If INSN == NULL, we want a real insn. */
587 insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
588 length, fields, insn != NULL);
589 if (! insn)
590 return NULL;
591
592 cgen_get_insn_operands (cd, insn, fields, indices);
593 return insn;
594 }
595
596 /* Allow signed overflow of instruction fields. */
597 void
598 cgen_set_signed_overflow_ok (CGEN_CPU_DESC cd)
599 {
600 cd->signed_overflow_ok_p = 1;
601 }
602
603 /* Generate an error message if a signed field in an instruction overflows. */
604 void
605 cgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd)
606 {
607 cd->signed_overflow_ok_p = 0;
608 }
609
610 /* Will an error message be generated if a signed field in an instruction overflows ? */
611 unsigned int
612 cgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
613 {
614 return cd->signed_overflow_ok_p;
615 }