cgen-ibld.in revision 1.8
1/* Instruction building/extraction support for @arch@. -*- C -*- 2 3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator. 4 - the resultant file is machine generated, cgen-ibld.in isn't 5 6 Copyright (C) 1996-2022 Free Software Foundation, Inc. 7 8 This file is part of libopcodes. 9 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. 14 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. 19 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. */ 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" 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" 38 39#undef min 40#define min(a,b) ((a) < (b) ? (a) : (b)) 41#undef max 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 48 (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int, 49 unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR); 50static const char * insert_insn_normal 51 (CGEN_CPU_DESC, const CGEN_INSN *, 52 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma); 53static 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 *); 57static 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 61static 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 65static CGEN_INLINE void insert_1 66 (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *); 67static CGEN_INLINE int fill_cache 68 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma); 69static CGEN_INLINE long extract_1 70 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma); 71#endif 72 73/* Operand insertion. */ 74 75#if ! CGEN_INT_INSN_P 76 77/* Subroutine of insert_normal. */ 78 79static CGEN_INLINE void 80insert_1 (CGEN_CPU_DESC cd, 81 unsigned long value, 82 int start, 83 int length, 84 int word_length, 85 unsigned char *bufp) 86{ 87 unsigned long x, mask; 88 int shift; 89 90 x = cgen_get_insn_value (cd, bufp, word_length, cd->endian); 91 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); 99 100 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian); 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 * 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) 131{ 132 static char errbuf[100]; 133 unsigned long mask; 134 135 /* If LENGTH is zero, this operand doesn't contribute to the value. */ 136 if (length == 0) 137 return NULL; 138 139 /* Written this way to avoid undefined behaviour. */ 140 mask = (1UL << (length - 1) << 1) - 1; 141 142 if (word_length > 8 * sizeof (CGEN_INSN_INT)) 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. */ 155 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT)) 156 { 157 long minval = - (1UL << (length - 1)); 158 unsigned long maxval = mask; 159 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; 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) 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; 197 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 { 212 int shift_within_word, shift_to_word, shift; 213 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. */ 218 if (CGEN_INSN_LSB0_P) 219 shift_within_word = start + 1 - length; 220 else 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; 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). 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. */ 247 248static const char * 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) 254{ 255 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 256 unsigned long value; 257 const CGEN_SYNTAX_CHAR_TYPE * syn; 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 267 put_insn_int_value (cd, buffer, cd->base_insn_bitsize, 268 CGEN_FIELDS_BITSIZE (fields), value); 269 270#else 271 272 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize, 273 (unsigned) CGEN_FIELDS_BITSIZE (fields)), 274 value, cd->insn_endian); 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 283 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn) 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} 298 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. */ 302 303static void 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) 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. */ 318 CGEN_INSN_INT mask = length == 0 ? 0 : (1UL << (length - 1) << 1) - 1; 319 320 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift); 321 } 322} 323#endif 324 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 336fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 337 CGEN_EXTRACT_INFO *ex_info, 338 int offset, 339 int bytes, 340 bfd_vma pc) 341{ 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; 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 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) 387{ 388 unsigned long x; 389 int shift; 390 391 x = cgen_get_insn_value (cd, bufp, word_length, cd->endian); 392 393 if (CGEN_INSN_LSB0_P) 394 shift = (start + 1) - length; 395 else 396 shift = (word_length - (start + length)); 397 return x >> shift; 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 423extract_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) 442{ 443 long value, mask; 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 453 if (word_length > 8 * sizeof (CGEN_INSN_INT)) 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 { 460 if (word_offset + word_length > total_length) 461 word_length = total_length - word_offset; 462 } 463 464 /* Does the value reside in INSN_VALUE, and at the right alignment? */ 465 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 } 473 474#if ! CGEN_INT_INSN_P 475 476 else 477 { 478 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8; 479 480 if (word_length > 8 * sizeof (CGEN_INSN_INT)) 481 abort (); 482 483 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0) 484 { 485 *valuep = 0; 486 return 0; 487 } 488 489 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc); 490 } 491 492#endif /* ! CGEN_INT_INSN_P */ 493 494 /* Written this way to avoid undefined behaviour. */ 495 mask = (1UL << (length - 1) << 1) - 1; 496 497 value &= mask; 498 /* sign extend? */ 499 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED) 500 && (value & (1UL << (length - 1)))) 501 value |= ~mask; 502 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 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) 524{ 525 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 526 const CGEN_SYNTAX_CHAR_TYPE *syn; 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 549/* Machine generated code added here. */ 550