x86-64: Fix support for APX NF TLS IE with 2 operands
[binutils-gdb.git] / opcodes / cgen-ibld.in
blob77b7aae398ceb753b8c9de760db5fb5529e153be
1 /* Instruction building/extraction support for @arch@. -*- C -*-
3    THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4    - the resultant file is machine generated, cgen-ibld.in isn't
6    Copyright (C) 1996-2024 Free Software Foundation, Inc.
8    This file is part of libopcodes.
10    This library is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3, or (at your option)
13    any later version.
15    It is distributed in the hope that it will be useful, but WITHOUT
16    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18    License for more details.
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software Foundation, Inc.,
22    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
24 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
25    Keep that in mind.  */
27 #include "sysdep.h"
28 #include <stdio.h>
29 #include "ansidecl.h"
30 #include "dis-asm.h"
31 #include "bfd.h"
32 #include "symcat.h"
33 #include "@prefix@-desc.h"
34 #include "@prefix@-opc.h"
35 #include "cgen/basic-modes.h"
36 #include "opintl.h"
37 #include "safe-ctype.h"
39 #undef  min
40 #define min(a,b) ((a) < (b) ? (a) : (b))
41 #undef  max
42 #define max(a,b) ((a) > (b) ? (a) : (b))
44 /* Used by the ifield rtx function.  */
45 #define FLD(f) (fields->f)
47 static const char * insert_normal
48   (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
49    unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
50 static const char * insert_insn_normal
51   (CGEN_CPU_DESC, const CGEN_INSN *,
52    CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
53 static int extract_normal
54   (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
55    unsigned int, unsigned int, unsigned int, unsigned int,
56    unsigned int, unsigned int, bfd_vma, long *);
57 static int extract_insn_normal
58   (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59    CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
60 #if CGEN_INT_INSN_P
61 static void put_insn_int_value
62   (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
63 #endif
64 #if ! CGEN_INT_INSN_P
65 static CGEN_INLINE void insert_1
66   (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
67 static CGEN_INLINE int fill_cache
68   (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
69 static CGEN_INLINE long extract_1
70   (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
71 #endif
73 /* Operand insertion.  */
75 #if ! CGEN_INT_INSN_P
77 /* Subroutine of insert_normal.  */
79 static CGEN_INLINE void
80 insert_1 (CGEN_CPU_DESC cd,
81           unsigned long value,
82           int start,
83           int length,
84           int word_length,
85           unsigned char *bufp)
87   unsigned long x, mask;
88   int shift;
90   x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
92   /* Written this way to avoid undefined behaviour.  */
93   mask = (1UL << (length - 1) << 1) - 1;
94   if (CGEN_INSN_LSB0_P)
95     shift = (start + 1) - length;
96   else
97     shift = (word_length - (start + length));
98   x = (x & ~(mask << shift)) | ((value & mask) << shift);
100   cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian);
103 #endif /* ! CGEN_INT_INSN_P */
105 /* Default insertion routine.
107    ATTRS is a mask of the boolean attributes.
108    WORD_OFFSET is the offset in bits from the start of the insn of the value.
109    WORD_LENGTH is the length of the word in bits in which the value resides.
110    START is the starting bit number in the word, architecture origin.
111    LENGTH is the length of VALUE in bits.
112    TOTAL_LENGTH is the total length of the insn in bits.
114    The result is an error message or NULL if success.  */
116 /* ??? This duplicates functionality with bfd's howto table and
117    bfd_install_relocation.  */
118 /* ??? This doesn't handle bfd_vma's.  Create another function when
119    necessary.  */
121 static const char *
122 insert_normal (CGEN_CPU_DESC cd,
123                long value,
124                unsigned int attrs,
125                unsigned int word_offset,
126                unsigned int start,
127                unsigned int length,
128                unsigned int word_length,
129                unsigned int total_length,
130                CGEN_INSN_BYTES_PTR buffer)
132   static char errbuf[100];
133   unsigned long mask;
135   /* If LENGTH is zero, this operand doesn't contribute to the value.  */
136   if (length == 0)
137     return NULL;
139   /* Written this way to avoid undefined behaviour.  */
140   mask = (1UL << (length - 1) << 1) - 1;
142   if (word_length > 8 * sizeof (CGEN_INSN_INT))
143     abort ();
145   /* For architectures with insns smaller than the base-insn-bitsize,
146      word_length may be too big.  */
147   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
148     {
149       if (word_offset == 0
150           && word_length > total_length)
151         word_length = total_length;
152     }
154   /* Ensure VALUE will fit.  */
155   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
156     {
157       long minval = - (1UL << (length - 1));
158       unsigned long maxval = mask;
160       if ((value > 0 && (unsigned long) value > maxval)
161           || value < minval)
162         {
163           /* xgettext:c-format */
164           sprintf (errbuf,
165                    _("operand out of range (%ld not between %ld and %lu)"),
166                    value, minval, maxval);
167           return errbuf;
168         }
169     }
170   else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
171     {
172       unsigned long maxval = mask;
173       unsigned long val = (unsigned long) value;
175       /* For hosts with a word size > 32 check to see if value has been sign
176          extended beyond 32 bits.  If so then ignore these higher sign bits
177          as the user is attempting to store a 32-bit signed value into an
178          unsigned 32-bit field which is allowed.  */
179       if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
180         val &= 0xFFFFFFFF;
182       if (val > maxval)
183         {
184           /* xgettext:c-format */
185           sprintf (errbuf,
186                    _("operand out of range (0x%lx not between 0 and 0x%lx)"),
187                    val, maxval);
188           return errbuf;
189         }
190     }
191   else
192     {
193       if (! cgen_signed_overflow_ok_p (cd))
194         {
195           long minval = - (1UL << (length - 1));
196           long maxval =   (1UL << (length - 1)) - 1;
198           if (value < minval || value > maxval)
199             {
200               sprintf
201                 /* xgettext:c-format */
202                 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
203                  value, minval, maxval);
204               return errbuf;
205             }
206         }
207     }
209 #if CGEN_INT_INSN_P
211   {
212     int shift_within_word, shift_to_word, shift;
214     /* How to shift the value to BIT0 of the word.  */
215     shift_to_word = total_length - (word_offset + word_length);
217     /* How to shift the value to the field within the word.  */
218     if (CGEN_INSN_LSB0_P)
219       shift_within_word = start + 1 - length;
220     else
221       shift_within_word = word_length - start - length;
223     /* The total SHIFT, then mask in the value.  */
224     shift = shift_to_word + shift_within_word;
225     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
226   }
228 #else /* ! CGEN_INT_INSN_P */
230   {
231     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
233     insert_1 (cd, value, start, length, word_length, bufp);
234   }
236 #endif /* ! CGEN_INT_INSN_P */
238   return NULL;
241 /* Default insn builder (insert handler).
242    The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
243    that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
244    recorded in host byte order, otherwise BUFFER is an array of bytes
245    and the value is recorded in target byte order).
246    The result is an error message or NULL if success.  */
248 static const char *
249 insert_insn_normal (CGEN_CPU_DESC cd,
250                     const CGEN_INSN * insn,
251                     CGEN_FIELDS * fields,
252                     CGEN_INSN_BYTES_PTR buffer,
253                     bfd_vma pc)
255   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
256   unsigned long value;
257   const CGEN_SYNTAX_CHAR_TYPE * syn;
259   CGEN_INIT_INSERT (cd);
260   value = CGEN_INSN_BASE_VALUE (insn);
262   /* If we're recording insns as numbers (rather than a string of bytes),
263      target byte order handling is deferred until later.  */
265 #if CGEN_INT_INSN_P
267   put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
268                       CGEN_FIELDS_BITSIZE (fields), value);
270 #else
272   cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
273                                         (unsigned) CGEN_FIELDS_BITSIZE (fields)),
274                        value, cd->insn_endian);
276 #endif /* ! CGEN_INT_INSN_P */
278   /* ??? It would be better to scan the format's fields.
279      Still need to be able to insert a value based on the operand though;
280      e.g. storing a branch displacement that got resolved later.
281      Needs more thought first.  */
283   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
284     {
285       const char *errmsg;
287       if (CGEN_SYNTAX_CHAR_P (* syn))
288         continue;
290       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
291                                        fields, buffer, pc);
292       if (errmsg)
293         return errmsg;
294     }
296   return NULL;
299 #if CGEN_INT_INSN_P
300 /* Cover function to store an insn value into an integral insn.  Must go here
301    because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
303 static void
304 put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
305                     CGEN_INSN_BYTES_PTR buf,
306                     int length,
307                     int insn_length,
308                     CGEN_INSN_INT value)
310   /* For architectures with insns smaller than the base-insn-bitsize,
311      length may be too big.  */
312   if (length > insn_length)
313     *buf = value;
314   else
315     {
316       int shift = insn_length - length;
317       /* Written this way to avoid undefined behaviour.  */
318       CGEN_INSN_INT mask = length == 0 ? 0 : (1UL << (length - 1) << 1) - 1;
320       *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
321     }
323 #endif
325 /* Operand extraction.  */
327 #if ! CGEN_INT_INSN_P
329 /* Subroutine of extract_normal.
330    Ensure sufficient bytes are cached in EX_INFO.
331    OFFSET is the offset in bytes from the start of the insn of the value.
332    BYTES is the length of the needed value.
333    Returns 1 for success, 0 for failure.  */
335 static CGEN_INLINE int
336 fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
337             CGEN_EXTRACT_INFO *ex_info,
338             int offset,
339             int bytes,
340             bfd_vma pc)
342   /* It's doubtful that the middle part has already been fetched so
343      we don't optimize that case.  kiss.  */
344   unsigned int mask;
345   disassemble_info *info = (disassemble_info *) ex_info->dis_info;
347   /* First do a quick check.  */
348   mask = (1 << bytes) - 1;
349   if (((ex_info->valid >> offset) & mask) == mask)
350     return 1;
352   /* Search for the first byte we need to read.  */
353   for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
354     if (! (mask & ex_info->valid))
355       break;
357   if (bytes)
358     {
359       int status;
361       pc += offset;
362       status = (*info->read_memory_func)
363         (pc, ex_info->insn_bytes + offset, bytes, info);
365       if (status != 0)
366         {
367           (*info->memory_error_func) (status, pc, info);
368           return 0;
369         }
371       ex_info->valid |= ((1 << bytes) - 1) << offset;
372     }
374   return 1;
377 /* Subroutine of extract_normal.  */
379 static CGEN_INLINE long
380 extract_1 (CGEN_CPU_DESC cd,
381            CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
382            int start,
383            int length,
384            int word_length,
385            unsigned char *bufp,
386            bfd_vma pc ATTRIBUTE_UNUSED)
388   unsigned long x;
389   int shift;
391   x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
393   if (CGEN_INSN_LSB0_P)
394     shift = (start + 1) - length;
395   else
396     shift = (word_length - (start + length));
397   return x >> shift;
400 #endif /* ! CGEN_INT_INSN_P */
402 /* Default extraction routine.
404    INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
405    or sometimes less for cases like the m32r where the base insn size is 32
406    but some insns are 16 bits.
407    ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
408    but for generality we take a bitmask of all of them.
409    WORD_OFFSET is the offset in bits from the start of the insn of the value.
410    WORD_LENGTH is the length of the word in bits in which the value resides.
411    START is the starting bit number in the word, architecture origin.
412    LENGTH is the length of VALUE in bits.
413    TOTAL_LENGTH is the total length of the insn in bits.
415    Returns 1 for success, 0 for failure.  */
417 /* ??? The return code isn't properly used.  wip.  */
419 /* ??? This doesn't handle bfd_vma's.  Create another function when
420    necessary.  */
422 static int
423 extract_normal (CGEN_CPU_DESC cd,
424 #if ! CGEN_INT_INSN_P
425                 CGEN_EXTRACT_INFO *ex_info,
426 #else
427                 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
428 #endif
429                 CGEN_INSN_INT insn_value,
430                 unsigned int attrs,
431                 unsigned int word_offset,
432                 unsigned int start,
433                 unsigned int length,
434                 unsigned int word_length,
435                 unsigned int total_length,
436 #if ! CGEN_INT_INSN_P
437                 bfd_vma pc,
438 #else
439                 bfd_vma pc ATTRIBUTE_UNUSED,
440 #endif
441                 long *valuep)
443   long value, mask;
445   /* If LENGTH is zero, this operand doesn't contribute to the value
446      so give it a standard value of zero.  */
447   if (length == 0)
448     {
449       *valuep = 0;
450       return 1;
451     }
453   if (word_length > 8 * sizeof (CGEN_INSN_INT))
454     abort ();
456   /* For architectures with insns smaller than the insn-base-bitsize,
457      word_length may be too big.  */
458   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
459     {
460       if (word_offset + word_length > total_length)
461         word_length = total_length - word_offset;
462     }
464   /* Does the value reside in INSN_VALUE, and at the right alignment?  */
466   if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
467     {
468       if (CGEN_INSN_LSB0_P)
469         value = insn_value >> ((word_offset + start + 1) - length);
470       else
471         value = insn_value >> (total_length - ( word_offset + start + length));
472     }
474 #if ! CGEN_INT_INSN_P
476   else
477     {
478       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
480       if (word_length > 8 * sizeof (CGEN_INSN_INT))
481         abort ();
483       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
484         {
485           *valuep = 0;
486           return 0;
487         }
489       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
490     }
492 #endif /* ! CGEN_INT_INSN_P */
494   /* Written this way to avoid undefined behaviour.  */
495   mask = (1UL << (length - 1) << 1) - 1;
497   value &= mask;
498   /* sign extend? */
499   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
500       && (value & (1UL << (length - 1))))
501     value |= ~mask;
503   *valuep = value;
505   return 1;
508 /* Default insn extractor.
510    INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
511    The extracted fields are stored in FIELDS.
512    EX_INFO is used to handle reading variable length insns.
513    Return the length of the insn in bits, or 0 if no match,
514    or -1 if an error occurs fetching data (memory_error_func will have
515    been called).  */
517 static int
518 extract_insn_normal (CGEN_CPU_DESC cd,
519                      const CGEN_INSN *insn,
520                      CGEN_EXTRACT_INFO *ex_info,
521                      CGEN_INSN_INT insn_value,
522                      CGEN_FIELDS *fields,
523                      bfd_vma pc)
525   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
526   const CGEN_SYNTAX_CHAR_TYPE *syn;
528   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
530   CGEN_INIT_EXTRACT (cd);
532   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
533     {
534       int length;
536       if (CGEN_SYNTAX_CHAR_P (*syn))
537         continue;
539       length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
540                                         ex_info, insn_value, fields, pc);
541       if (length <= 0)
542         return length;
543     }
545   /* We recognized and successfully extracted this insn.  */
546   return CGEN_INSN_BITSIZE (insn);
549 /* Machine generated code added here.  */