]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/cgen-ibld.in
PR26449, PR26450 UBSAN: frv-ibld.c:135 left shift
[thirdparty/binutils-gdb.git] / opcodes / cgen-ibld.in
CommitLineData
f6e6b40f
BE
1/* Instruction building/extraction support for @arch@. -*- C -*-
2
47b0e7ad
NC
3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4 - the resultant file is machine generated, cgen-ibld.in isn't
f6e6b40f 5
b3adc24a 6 Copyright (C) 1996-2020 Free Software Foundation, Inc.
f6e6b40f 7
9b201bb5 8 This file is part of libopcodes.
f6e6b40f 9
9b201bb5 10 This library is free software; you can redistribute it and/or modify
47b0e7ad 11 it under the terms of the GNU General Public License as published by
9b201bb5 12 the Free Software Foundation; either version 3, or (at your option)
47b0e7ad 13 any later version.
f6e6b40f 14
9b201bb5
NC
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.
f6e6b40f 19
47b0e7ad
NC
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. */
f6e6b40f
BE
23
24/* ??? Eventually more and more of this stuff can go to cpu-independent files.
25 Keep that in mind. */
26
27#include "sysdep.h"
f6e6b40f
BE
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"
fe8afbc4 35#include "cgen/basic-modes.h"
f6e6b40f 36#include "opintl.h"
37111cc7 37#include "safe-ctype.h"
f6e6b40f 38
47b0e7ad 39#undef min
f6e6b40f 40#define min(a,b) ((a) < (b) ? (a) : (b))
47b0e7ad 41#undef max
f6e6b40f
BE
42#define max(a,b) ((a) > (b) ? (a) : (b))
43
44/* Used by the ifield rtx function. */
45#define FLD(f) (fields->f)
46
47static const char * insert_normal
10e05405
MM
48 (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
49 unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
f6e6b40f 50static const char * insert_insn_normal
10e05405
MM
51 (CGEN_CPU_DESC, const CGEN_INSN *,
52 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
f6e6b40f 53static int extract_normal
10e05405
MM
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 *);
f6e6b40f 57static int extract_insn_normal
10e05405
MM
58 (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
0e2ee3ca 60#if CGEN_INT_INSN_P
6bb95a0f 61static void put_insn_int_value
10e05405 62 (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
0e2ee3ca
NC
63#endif
64#if ! CGEN_INT_INSN_P
65static CGEN_INLINE void insert_1
10e05405 66 (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
0e2ee3ca 67static CGEN_INLINE int fill_cache
10e05405 68 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma);
0e2ee3ca 69static CGEN_INLINE long extract_1
10e05405 70 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
0e2ee3ca 71#endif
f6e6b40f
BE
72\f
73/* Operand insertion. */
74
75#if ! CGEN_INT_INSN_P
76
77/* Subroutine of insert_normal. */
78
79static CGEN_INLINE void
10e05405
MM
80insert_1 (CGEN_CPU_DESC cd,
81 unsigned long value,
44d221f0
MM
82 int start,
83 int length,
84 int word_length,
10e05405 85 unsigned char *bufp)
f6e6b40f 86{
a1e60a1b 87 unsigned long x, mask;
f6e6b40f 88 int shift;
f6e6b40f 89
e9bffec9 90 x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
f6e6b40f
BE
91
92 /* Written this way to avoid undefined behaviour. */
a1e60a1b 93 mask = (1UL << (length - 1) << 1) - 1;
f6e6b40f
BE
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);
99
e9bffec9 100 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian);
f6e6b40f
BE
101}
102
103#endif /* ! CGEN_INT_INSN_P */
104
105/* Default insertion routine.
106
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.
113
114 The result is an error message or NULL if success. */
115
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. */
120
121static const char *
10e05405
MM
122insert_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)
f6e6b40f
BE
131{
132 static char errbuf[100];
a1e60a1b 133 unsigned long mask;
f6e6b40f
BE
134
135 /* If LENGTH is zero, this operand doesn't contribute to the value. */
136 if (length == 0)
137 return NULL;
138
a1e60a1b
AM
139 /* Written this way to avoid undefined behaviour. */
140 mask = (1UL << (length - 1) << 1) - 1;
141
b7cd1872 142 if (word_length > 8 * sizeof (CGEN_INSN_INT))
f6e6b40f
BE
143 abort ();
144
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 }
153
154 /* Ensure VALUE will fit. */
17f0ac84
GK
155 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
156 {
157 long minval = - (1L << (length - 1));
158 unsigned long maxval = mask;
43e65147 159
17f0ac84
GK
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))
f6e6b40f
BE
171 {
172 unsigned long maxval = mask;
ed963e2d
NC
173 unsigned long val = (unsigned long) value;
174
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;
181
182 if (val > maxval)
f6e6b40f
BE
183 {
184 /* xgettext:c-format */
185 sprintf (errbuf,
ed963e2d
NC
186 _("operand out of range (0x%lx not between 0 and 0x%lx)"),
187 val, maxval);
f6e6b40f
BE
188 return errbuf;
189 }
190 }
191 else
192 {
193 if (! cgen_signed_overflow_ok_p (cd))
194 {
195 long minval = - (1L << (length - 1));
196 long maxval = (1L << (length - 1)) - 1;
43e65147 197
f6e6b40f
BE
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 }
208
209#if CGEN_INT_INSN_P
210
211 {
a143b004 212 int shift_within_word, shift_to_word, shift;
f6e6b40f 213
a143b004
AB
214 /* How to shift the value to BIT0 of the word. */
215 shift_to_word = total_length - (word_offset + word_length);
216
217 /* How to shift the value to the field within the word. */
f6e6b40f 218 if (CGEN_INSN_LSB0_P)
a143b004 219 shift_within_word = start + 1 - length;
f6e6b40f 220 else
a143b004
AB
221 shift_within_word = word_length - start - length;
222
223 /* The total SHIFT, then mask in the value. */
224 shift = shift_to_word + shift_within_word;
f6e6b40f
BE
225 *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
226 }
227
228#else /* ! CGEN_INT_INSN_P */
229
230 {
231 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
232
233 insert_1 (cd, value, start, length, word_length, bufp);
234 }
235
236#endif /* ! CGEN_INT_INSN_P */
237
238 return NULL;
239}
240
241/* Default insn builder (insert handler).
0e70c820
BE
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).
f6e6b40f
BE
246 The result is an error message or NULL if success. */
247
248static const char *
10e05405
MM
249insert_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)
f6e6b40f
BE
254{
255 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
256 unsigned long value;
4a9f416d 257 const CGEN_SYNTAX_CHAR_TYPE * syn;
f6e6b40f
BE
258
259 CGEN_INIT_INSERT (cd);
260 value = CGEN_INSN_BASE_VALUE (insn);
261
262 /* If we're recording insns as numbers (rather than a string of bytes),
263 target byte order handling is deferred until later. */
264
265#if CGEN_INT_INSN_P
266
6bb95a0f
DB
267 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
268 CGEN_FIELDS_BITSIZE (fields), value);
f6e6b40f
BE
269
270#else
271
0e2ee3ca 272 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
e9bffec9
JM
273 (unsigned) CGEN_FIELDS_BITSIZE (fields)),
274 value, cd->insn_endian);
f6e6b40f
BE
275
276#endif /* ! CGEN_INT_INSN_P */
277
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. */
282
4a9f416d 283 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
f6e6b40f
BE
284 {
285 const char *errmsg;
286
287 if (CGEN_SYNTAX_CHAR_P (* syn))
288 continue;
289
290 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
291 fields, buffer, pc);
292 if (errmsg)
293 return errmsg;
294 }
295
296 return NULL;
297}
6bb95a0f 298
0e2ee3ca 299#if CGEN_INT_INSN_P
6bb95a0f 300/* Cover function to store an insn value into an integral insn. Must go here
47b0e7ad 301 because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
6bb95a0f
DB
302
303static void
10e05405
MM
304put_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)
6bb95a0f
DB
309{
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. */
a1e60a1b 318 CGEN_INSN_INT mask = length == 0 ? 0 : (1UL << (length - 1) << 1) - 1;
47b0e7ad 319
6bb95a0f
DB
320 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
321 }
322}
0e2ee3ca 323#endif
f6e6b40f
BE
324\f
325/* Operand extraction. */
326
327#if ! CGEN_INT_INSN_P
328
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. */
334
335static CGEN_INLINE int
10e05405
MM
336fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
337 CGEN_EXTRACT_INFO *ex_info,
44d221f0
MM
338 int offset,
339 int bytes,
10e05405 340 bfd_vma pc)
f6e6b40f
BE
341{
342 /* It's doubtful that the middle part has already been fetched so
343 we don't optimize that case. kiss. */
0e2ee3ca 344 unsigned int mask;
f6e6b40f
BE
345 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
346
347 /* First do a quick check. */
348 mask = (1 << bytes) - 1;
349 if (((ex_info->valid >> offset) & mask) == mask)
350 return 1;
351
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;
356
357 if (bytes)
358 {
359 int status;
360
361 pc += offset;
362 status = (*info->read_memory_func)
363 (pc, ex_info->insn_bytes + offset, bytes, info);
364
365 if (status != 0)
366 {
367 (*info->memory_error_func) (status, pc, info);
368 return 0;
369 }
370
371 ex_info->valid |= ((1 << bytes) - 1) << offset;
372 }
373
374 return 1;
375}
376
377/* Subroutine of extract_normal. */
378
379static CGEN_INLINE long
10e05405
MM
380extract_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)
f6e6b40f 387{
aed80dae 388 unsigned long x;
f6e6b40f 389 int shift;
47b0e7ad 390
e9bffec9 391 x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
e333d2c4 392
f6e6b40f
BE
393 if (CGEN_INSN_LSB0_P)
394 shift = (start + 1) - length;
395 else
396 shift = (word_length - (start + length));
aed80dae 397 return x >> shift;
f6e6b40f
BE
398}
399
400#endif /* ! CGEN_INT_INSN_P */
401
402/* Default extraction routine.
403
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.
414
415 Returns 1 for success, 0 for failure. */
416
417/* ??? The return code isn't properly used. wip. */
418
419/* ??? This doesn't handle bfd_vma's. Create another function when
420 necessary. */
421
422static int
44d221f0 423extract_normal (CGEN_CPU_DESC cd,
f6e6b40f 424#if ! CGEN_INT_INSN_P
10e05405 425 CGEN_EXTRACT_INFO *ex_info,
f6e6b40f 426#else
10e05405 427 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
f6e6b40f 428#endif
10e05405
MM
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,
f6e6b40f 436#if ! CGEN_INT_INSN_P
10e05405 437 bfd_vma pc,
f6e6b40f 438#else
10e05405 439 bfd_vma pc ATTRIBUTE_UNUSED,
f6e6b40f 440#endif
10e05405 441 long *valuep)
f6e6b40f 442{
fc7bc883 443 long value, mask;
f6e6b40f
BE
444
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 }
452
b7cd1872 453 if (word_length > 8 * sizeof (CGEN_INSN_INT))
f6e6b40f
BE
454 abort ();
455
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 {
54d46aca
DD
460 if (word_offset + word_length > total_length)
461 word_length = total_length - word_offset;
f6e6b40f
BE
462 }
463
a00ad97d 464 /* Does the value reside in INSN_VALUE, and at the right alignment? */
f6e6b40f 465
a00ad97d 466 if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
f6e6b40f 467 {
f6e6b40f 468 if (CGEN_INSN_LSB0_P)
6bb95a0f 469 value = insn_value >> ((word_offset + start + 1) - length);
f6e6b40f 470 else
6bb95a0f 471 value = insn_value >> (total_length - ( word_offset + start + length));
f6e6b40f
BE
472 }
473
474#if ! CGEN_INT_INSN_P
475
476 else
477 {
478 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
479
b7cd1872 480 if (word_length > 8 * sizeof (CGEN_INSN_INT))
f6e6b40f
BE
481 abort ();
482
483 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
2f5dd314
AM
484 {
485 *valuep = 0;
486 return 0;
487 }
f6e6b40f
BE
488
489 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
490 }
491
492#endif /* ! CGEN_INT_INSN_P */
493
aed80dae 494 /* Written this way to avoid undefined behaviour. */
a1e60a1b 495 mask = (1UL << (length - 1) << 1) - 1;
aed80dae
FCE
496
497 value &= mask;
498 /* sign extend? */
499 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
500 && (value & (1L << (length - 1))))
501 value |= ~mask;
502
f6e6b40f
BE
503 *valuep = value;
504
505 return 1;
506}
507
508/* Default insn extractor.
509
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). */
516
517static int
10e05405
MM
518extract_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)
f6e6b40f
BE
524{
525 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
4a9f416d 526 const CGEN_SYNTAX_CHAR_TYPE *syn;
f6e6b40f
BE
527
528 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
529
530 CGEN_INIT_EXTRACT (cd);
531
532 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
533 {
534 int length;
535
536 if (CGEN_SYNTAX_CHAR_P (*syn))
537 continue;
538
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 }
544
545 /* We recognized and successfully extracted this insn. */
546 return CGEN_INSN_BITSIZE (insn);
547}
548\f
47b0e7ad 549/* Machine generated code added here. */