xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/cgen-opc.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* CGEN generic opcode support.
2 
3    Copyright (C) 1996-2024 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 *
cgen_keyword_lookup_name(CGEN_KEYWORD * kt,const char * name)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 *
cgen_keyword_lookup_value(CGEN_KEYWORD * kt,int value)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
cgen_keyword_add(CGEN_KEYWORD * kt,CGEN_KEYWORD_ENTRY * ke)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
cgen_keyword_search_init(CGEN_KEYWORD * kt,const char * spec)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 *
cgen_keyword_search_next(CGEN_KEYWORD_SEARCH * search)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
hash_keyword_name(const CGEN_KEYWORD * kt,const char * name,int case_sensitive_p)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
hash_keyword_value(const CGEN_KEYWORD * kt,unsigned int value)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
build_keyword_hash_tables(CGEN_KEYWORD * kt)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 
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 *
cgen_hw_lookup_by_name(CGEN_CPU_DESC cd,const char * name)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 *
cgen_hw_lookup_by_num(CGEN_CPU_DESC cd,unsigned int hwnum)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 
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 *
cgen_operand_lookup_by_name(CGEN_CPU_DESC cd,const char * name)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 *
cgen_operand_lookup_by_num(CGEN_CPU_DESC cd,int opnum)320 cgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum)
321 {
322   return cd->operand_table.entries[opnum];
323 }
324 
325 /* Instruction support.  */
326 
327 /* Return number of instructions.  This includes any added at runtime.  */
328 
329 int
cgen_insn_count(CGEN_CPU_DESC cd)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
cgen_macro_insn_count(CGEN_CPU_DESC cd)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
cgen_get_insn_value(CGEN_CPU_DESC cd,unsigned char * buf,int length,int endian)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
cgen_put_insn_value(CGEN_CPU_DESC cd,unsigned char * buf,int length,CGEN_INSN_INT value,int endian)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 
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 *
cgen_lookup_insn(CGEN_CPU_DESC cd,const CGEN_INSN * insn,CGEN_INSN_INT insn_int_value,unsigned char * insn_bytes_value,int length,CGEN_FIELDS * fields,int alias_p)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
cgen_get_insn_operands(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const CGEN_FIELDS * fields,int * indices)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 *
cgen_lookup_get_insn_operands(CGEN_CPU_DESC cd,const CGEN_INSN * insn,CGEN_INSN_INT insn_int_value,unsigned char * insn_bytes_value,int length,int * indices,CGEN_FIELDS * fields)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
cgen_set_signed_overflow_ok(CGEN_CPU_DESC cd)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
cgen_clear_signed_overflow_ok(CGEN_CPU_DESC cd)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
cgen_signed_overflow_ok_p(CGEN_CPU_DESC cd)612 cgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
613 {
614   return cd->signed_overflow_ok_p;
615 }
616