[8833] | 1 | /* Allocate and read RTL for GNU C Compiler. |
---|
| 2 | Copyright (C) 1987, 1988, 1991, 1994 Free Software Foundation, Inc. |
---|
| 3 | |
---|
| 4 | This file is part of GNU CC. |
---|
| 5 | |
---|
| 6 | GNU CC is free software; you can redistribute it and/or modify |
---|
| 7 | it under the terms of the GNU General Public License as published by |
---|
| 8 | the Free Software Foundation; either version 2, or (at your option) |
---|
| 9 | any later version. |
---|
| 10 | |
---|
| 11 | GNU CC is distributed in the hope that it will be useful, |
---|
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 14 | GNU General Public License for more details. |
---|
| 15 | |
---|
| 16 | You should have received a copy of the GNU General Public License |
---|
| 17 | along with GNU CC; see the file COPYING. If not, write to |
---|
| 18 | the Free Software Foundation, 59 Temple Place - Suite 330, |
---|
| 19 | Boston, MA 02111-1307, USA. */ |
---|
| 20 | |
---|
| 21 | |
---|
| 22 | #include "config.h" |
---|
| 23 | #include <ctype.h> |
---|
| 24 | #include <stdio.h> |
---|
| 25 | #include "rtl.h" |
---|
| 26 | #include "real.h" |
---|
| 27 | |
---|
| 28 | #include "obstack.h" |
---|
| 29 | #define obstack_chunk_alloc xmalloc |
---|
| 30 | #define obstack_chunk_free free |
---|
| 31 | |
---|
| 32 | /* Obstack used for allocating RTL objects. |
---|
| 33 | Between functions, this is the permanent_obstack. |
---|
| 34 | While parsing and expanding a function, this is maybepermanent_obstack |
---|
| 35 | so we can save it if it is an inline function. |
---|
| 36 | During optimization and output, this is function_obstack. */ |
---|
| 37 | |
---|
| 38 | extern struct obstack *rtl_obstack; |
---|
| 39 | |
---|
| 40 | #if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT |
---|
| 41 | extern long atol(); |
---|
| 42 | #endif |
---|
| 43 | |
---|
| 44 | /* Indexed by rtx code, gives number of operands for an rtx with that code. |
---|
| 45 | Does NOT include rtx header data (code and links). |
---|
| 46 | This array is initialized in init_rtl. */ |
---|
| 47 | |
---|
| 48 | int rtx_length[NUM_RTX_CODE + 1]; |
---|
| 49 | |
---|
| 50 | /* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */ |
---|
| 51 | |
---|
| 52 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME , |
---|
| 53 | |
---|
| 54 | char *rtx_name[] = { |
---|
| 55 | #include "rtl.def" /* rtl expressions are documented here */ |
---|
| 56 | }; |
---|
| 57 | |
---|
| 58 | #undef DEF_RTL_EXPR |
---|
| 59 | |
---|
| 60 | /* Indexed by machine mode, gives the name of that machine mode. |
---|
| 61 | This name does not include the letters "mode". */ |
---|
| 62 | |
---|
| 63 | #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) NAME, |
---|
| 64 | |
---|
| 65 | char *mode_name[(int) MAX_MACHINE_MODE] = { |
---|
| 66 | #include "machmode.def" |
---|
| 67 | |
---|
| 68 | #ifdef EXTRA_CC_MODES |
---|
| 69 | EXTRA_CC_NAMES |
---|
| 70 | #endif |
---|
| 71 | |
---|
| 72 | }; |
---|
| 73 | |
---|
| 74 | #undef DEF_MACHMODE |
---|
| 75 | |
---|
| 76 | /* Indexed by machine mode, gives the length of the mode, in bytes. |
---|
| 77 | GET_MODE_CLASS uses this. */ |
---|
| 78 | |
---|
| 79 | #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) CLASS, |
---|
| 80 | |
---|
| 81 | enum mode_class mode_class[(int) MAX_MACHINE_MODE] = { |
---|
| 82 | #include "machmode.def" |
---|
| 83 | }; |
---|
| 84 | |
---|
| 85 | #undef DEF_MACHMODE |
---|
| 86 | |
---|
| 87 | /* Indexed by machine mode, gives the length of the mode, in bytes. |
---|
| 88 | GET_MODE_SIZE uses this. */ |
---|
| 89 | |
---|
| 90 | #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) SIZE, |
---|
| 91 | |
---|
| 92 | int mode_size[(int) MAX_MACHINE_MODE] = { |
---|
| 93 | #include "machmode.def" |
---|
| 94 | }; |
---|
| 95 | |
---|
| 96 | #undef DEF_MACHMODE |
---|
| 97 | |
---|
| 98 | /* Indexed by machine mode, gives the length of the mode's subunit. |
---|
| 99 | GET_MODE_UNIT_SIZE uses this. */ |
---|
| 100 | |
---|
| 101 | #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) UNIT, |
---|
| 102 | |
---|
| 103 | int mode_unit_size[(int) MAX_MACHINE_MODE] = { |
---|
| 104 | #include "machmode.def" /* machine modes are documented here */ |
---|
| 105 | }; |
---|
| 106 | |
---|
| 107 | #undef DEF_MACHMODE |
---|
| 108 | |
---|
| 109 | /* Indexed by machine mode, gives next wider natural mode |
---|
| 110 | (QI -> HI -> SI -> DI, etc.) Widening multiply instructions |
---|
| 111 | use this. */ |
---|
| 112 | |
---|
| 113 | #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \ |
---|
| 114 | (enum machine_mode) WIDER, |
---|
| 115 | |
---|
| 116 | enum machine_mode mode_wider_mode[(int) MAX_MACHINE_MODE] = { |
---|
| 117 | #include "machmode.def" /* machine modes are documented here */ |
---|
| 118 | }; |
---|
| 119 | |
---|
| 120 | #undef DEF_MACHMODE |
---|
| 121 | |
---|
| 122 | /* Indexed by mode class, gives the narrowest mode for each class. */ |
---|
| 123 | |
---|
| 124 | enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS]; |
---|
| 125 | |
---|
| 126 | /* Indexed by rtx code, gives a sequence of operand-types for |
---|
| 127 | rtx's of that code. The sequence is a C string in which |
---|
| 128 | each character describes one operand. */ |
---|
| 129 | |
---|
| 130 | char *rtx_format[] = { |
---|
| 131 | /* "*" undefined. |
---|
| 132 | can cause a warning message |
---|
| 133 | "0" field is unused (or used in a phase-dependent manner) |
---|
| 134 | prints nothing |
---|
| 135 | "i" an integer |
---|
| 136 | prints the integer |
---|
| 137 | "n" like "i", but prints entries from `note_insn_name' |
---|
| 138 | "w" an integer of width HOST_BITS_PER_WIDE_INT |
---|
| 139 | prints the integer |
---|
| 140 | "s" a pointer to a string |
---|
| 141 | prints the string |
---|
| 142 | "S" like "s", but optional: |
---|
| 143 | the containing rtx may end before this operand |
---|
| 144 | "e" a pointer to an rtl expression |
---|
| 145 | prints the expression |
---|
| 146 | "E" a pointer to a vector that points to a number of rtl expressions |
---|
| 147 | prints a list of the rtl expressions |
---|
| 148 | "V" like "E", but optional: |
---|
| 149 | the containing rtx may end before this operand |
---|
| 150 | "u" a pointer to another insn |
---|
| 151 | prints the uid of the insn. */ |
---|
| 152 | |
---|
| 153 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT , |
---|
| 154 | #include "rtl.def" /* rtl expressions are defined here */ |
---|
| 155 | #undef DEF_RTL_EXPR |
---|
| 156 | }; |
---|
| 157 | |
---|
| 158 | /* Indexed by rtx code, gives a character representing the "class" of |
---|
| 159 | that rtx code. See rtl.def for documentation on the defined classes. */ |
---|
| 160 | |
---|
| 161 | char rtx_class[] = { |
---|
| 162 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS, |
---|
| 163 | #include "rtl.def" /* rtl expressions are defined here */ |
---|
| 164 | #undef DEF_RTL_EXPR |
---|
| 165 | }; |
---|
| 166 | |
---|
| 167 | /* Names for kinds of NOTEs and REG_NOTEs. */ |
---|
| 168 | |
---|
| 169 | char *note_insn_name[] = { 0 , "NOTE_INSN_DELETED", |
---|
| 170 | "NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END", |
---|
| 171 | "NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END", |
---|
| 172 | "NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP", |
---|
| 173 | "NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP", |
---|
| 174 | "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG", |
---|
| 175 | "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG"}; |
---|
| 176 | |
---|
| 177 | char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0", |
---|
| 178 | "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL", |
---|
| 179 | "REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED", |
---|
| 180 | "REG_CC_SETTER", "REG_CC_USER", "REG_LABEL", |
---|
| 181 | "REG_DEP_ANTI", "REG_DEP_OUTPUT" }; |
---|
| 182 | |
---|
| 183 | /* Allocate an rtx vector of N elements. |
---|
| 184 | Store the length, and initialize all elements to zero. */ |
---|
| 185 | |
---|
| 186 | rtvec |
---|
| 187 | rtvec_alloc (n) |
---|
| 188 | int n; |
---|
| 189 | { |
---|
| 190 | rtvec rt; |
---|
| 191 | int i; |
---|
| 192 | |
---|
| 193 | rt = (rtvec) obstack_alloc (rtl_obstack, |
---|
| 194 | sizeof (struct rtvec_def) |
---|
| 195 | + (( n - 1) * sizeof (rtunion))); |
---|
| 196 | |
---|
| 197 | /* clear out the vector */ |
---|
| 198 | PUT_NUM_ELEM(rt, n); |
---|
| 199 | for (i=0; i < n; i++) |
---|
| 200 | rt->elem[i].rtvec = NULL; /* @@ not portable due to rtunion */ |
---|
| 201 | |
---|
| 202 | return rt; |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | /* Allocate an rtx of code CODE. The CODE is stored in the rtx; |
---|
| 206 | all the rest is initialized to zero. */ |
---|
| 207 | |
---|
| 208 | rtx |
---|
| 209 | rtx_alloc (code) |
---|
| 210 | RTX_CODE code; |
---|
| 211 | { |
---|
| 212 | rtx rt; |
---|
| 213 | register struct obstack *ob = rtl_obstack; |
---|
| 214 | register int nelts = GET_RTX_LENGTH (code); |
---|
| 215 | register int length = sizeof (struct rtx_def) |
---|
| 216 | + (nelts - 1) * sizeof (rtunion); |
---|
| 217 | |
---|
| 218 | /* This function is called more than any other in GCC, |
---|
| 219 | so we manipulate the obstack directly. |
---|
| 220 | |
---|
| 221 | Even though rtx objects are word aligned, we may be sharing an obstack |
---|
| 222 | with tree nodes, which may have to be double-word aligned. So align |
---|
| 223 | our length to the alignment mask in the obstack. */ |
---|
| 224 | |
---|
| 225 | length = (length + ob->alignment_mask) & ~ ob->alignment_mask; |
---|
| 226 | |
---|
| 227 | if (ob->chunk_limit - ob->next_free < length) |
---|
| 228 | _obstack_newchunk (ob, length); |
---|
| 229 | rt = (rtx)ob->object_base; |
---|
| 230 | ob->next_free += length; |
---|
| 231 | ob->object_base = ob->next_free; |
---|
| 232 | |
---|
| 233 | /* We want to clear everything up to the FLD array. Normally, this is |
---|
| 234 | one int, but we don't want to assume that and it isn't very portable |
---|
| 235 | anyway; this is. */ |
---|
| 236 | |
---|
| 237 | length = (sizeof (struct rtx_def) - sizeof (rtunion) - 1) / sizeof (int); |
---|
| 238 | for (; length >= 0; length--) |
---|
| 239 | ((int *) rt)[length] = 0; |
---|
| 240 | |
---|
| 241 | PUT_CODE (rt, code); |
---|
| 242 | |
---|
| 243 | return rt; |
---|
| 244 | } |
---|
| 245 | |
---|
| 246 | /* Free the rtx X and all RTL allocated since X. */ |
---|
| 247 | |
---|
| 248 | void |
---|
| 249 | rtx_free (x) |
---|
| 250 | rtx x; |
---|
| 251 | { |
---|
| 252 | obstack_free (rtl_obstack, x); |
---|
| 253 | } |
---|
| 254 | |
---|
| 255 | /* Create a new copy of an rtx. |
---|
| 256 | Recursively copies the operands of the rtx, |
---|
| 257 | except for those few rtx codes that are sharable. */ |
---|
| 258 | |
---|
| 259 | rtx |
---|
| 260 | copy_rtx (orig) |
---|
| 261 | register rtx orig; |
---|
| 262 | { |
---|
| 263 | register rtx copy; |
---|
| 264 | register int i, j; |
---|
| 265 | register RTX_CODE code; |
---|
| 266 | register char *format_ptr; |
---|
| 267 | |
---|
| 268 | code = GET_CODE (orig); |
---|
| 269 | |
---|
| 270 | switch (code) |
---|
| 271 | { |
---|
| 272 | case REG: |
---|
| 273 | case QUEUED: |
---|
| 274 | case CONST_INT: |
---|
| 275 | case CONST_DOUBLE: |
---|
| 276 | case SYMBOL_REF: |
---|
| 277 | case CODE_LABEL: |
---|
| 278 | case PC: |
---|
| 279 | case CC0: |
---|
| 280 | case SCRATCH: |
---|
| 281 | /* SCRATCH must be shared because they represent distinct values. */ |
---|
| 282 | return orig; |
---|
| 283 | |
---|
| 284 | case CONST: |
---|
| 285 | /* CONST can be shared if it contains a SYMBOL_REF. If it contains |
---|
| 286 | a LABEL_REF, it isn't sharable. */ |
---|
| 287 | if (GET_CODE (XEXP (orig, 0)) == PLUS |
---|
| 288 | && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF |
---|
| 289 | && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT) |
---|
| 290 | return orig; |
---|
| 291 | break; |
---|
| 292 | |
---|
| 293 | /* A MEM with a constant address is not sharable. The problem is that |
---|
| 294 | the constant address may need to be reloaded. If the mem is shared, |
---|
| 295 | then reloading one copy of this mem will cause all copies to appear |
---|
| 296 | to have been reloaded. */ |
---|
| 297 | } |
---|
| 298 | |
---|
| 299 | copy = rtx_alloc (code); |
---|
| 300 | PUT_MODE (copy, GET_MODE (orig)); |
---|
| 301 | copy->in_struct = orig->in_struct; |
---|
| 302 | copy->volatil = orig->volatil; |
---|
| 303 | copy->unchanging = orig->unchanging; |
---|
| 304 | copy->integrated = orig->integrated; |
---|
| 305 | |
---|
| 306 | format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); |
---|
| 307 | |
---|
| 308 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) |
---|
| 309 | { |
---|
| 310 | switch (*format_ptr++) |
---|
| 311 | { |
---|
| 312 | case 'e': |
---|
| 313 | XEXP (copy, i) = XEXP (orig, i); |
---|
| 314 | if (XEXP (orig, i) != NULL) |
---|
| 315 | XEXP (copy, i) = copy_rtx (XEXP (orig, i)); |
---|
| 316 | break; |
---|
| 317 | |
---|
| 318 | case '0': |
---|
| 319 | case 'u': |
---|
| 320 | XEXP (copy, i) = XEXP (orig, i); |
---|
| 321 | break; |
---|
| 322 | |
---|
| 323 | case 'E': |
---|
| 324 | case 'V': |
---|
| 325 | XVEC (copy, i) = XVEC (orig, i); |
---|
| 326 | if (XVEC (orig, i) != NULL) |
---|
| 327 | { |
---|
| 328 | XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); |
---|
| 329 | for (j = 0; j < XVECLEN (copy, i); j++) |
---|
| 330 | XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j)); |
---|
| 331 | } |
---|
| 332 | break; |
---|
| 333 | |
---|
| 334 | case 'w': |
---|
| 335 | XWINT (copy, i) = XWINT (orig, i); |
---|
| 336 | break; |
---|
| 337 | |
---|
| 338 | case 'i': |
---|
| 339 | XINT (copy, i) = XINT (orig, i); |
---|
| 340 | break; |
---|
| 341 | |
---|
| 342 | case 's': |
---|
| 343 | case 'S': |
---|
| 344 | XSTR (copy, i) = XSTR (orig, i); |
---|
| 345 | break; |
---|
| 346 | |
---|
| 347 | default: |
---|
| 348 | abort (); |
---|
| 349 | } |
---|
| 350 | } |
---|
| 351 | return copy; |
---|
| 352 | } |
---|
| 353 | |
---|
| 354 | /* Similar to `copy_rtx' except that if MAY_SHARE is present, it is |
---|
| 355 | placed in the result directly, rather than being copied. */ |
---|
| 356 | |
---|
| 357 | rtx |
---|
| 358 | copy_most_rtx (orig, may_share) |
---|
| 359 | register rtx orig; |
---|
| 360 | register rtx may_share; |
---|
| 361 | { |
---|
| 362 | register rtx copy; |
---|
| 363 | register int i, j; |
---|
| 364 | register RTX_CODE code; |
---|
| 365 | register char *format_ptr; |
---|
| 366 | |
---|
| 367 | if (orig == may_share) |
---|
| 368 | return orig; |
---|
| 369 | |
---|
| 370 | code = GET_CODE (orig); |
---|
| 371 | |
---|
| 372 | switch (code) |
---|
| 373 | { |
---|
| 374 | case REG: |
---|
| 375 | case QUEUED: |
---|
| 376 | case CONST_INT: |
---|
| 377 | case CONST_DOUBLE: |
---|
| 378 | case SYMBOL_REF: |
---|
| 379 | case CODE_LABEL: |
---|
| 380 | case PC: |
---|
| 381 | case CC0: |
---|
| 382 | return orig; |
---|
| 383 | } |
---|
| 384 | |
---|
| 385 | copy = rtx_alloc (code); |
---|
| 386 | PUT_MODE (copy, GET_MODE (orig)); |
---|
| 387 | copy->in_struct = orig->in_struct; |
---|
| 388 | copy->volatil = orig->volatil; |
---|
| 389 | copy->unchanging = orig->unchanging; |
---|
| 390 | copy->integrated = orig->integrated; |
---|
| 391 | |
---|
| 392 | format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); |
---|
| 393 | |
---|
| 394 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) |
---|
| 395 | { |
---|
| 396 | switch (*format_ptr++) |
---|
| 397 | { |
---|
| 398 | case 'e': |
---|
| 399 | XEXP (copy, i) = XEXP (orig, i); |
---|
| 400 | if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share) |
---|
| 401 | XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share); |
---|
| 402 | break; |
---|
| 403 | |
---|
| 404 | case '0': |
---|
| 405 | case 'u': |
---|
| 406 | XEXP (copy, i) = XEXP (orig, i); |
---|
| 407 | break; |
---|
| 408 | |
---|
| 409 | case 'E': |
---|
| 410 | case 'V': |
---|
| 411 | XVEC (copy, i) = XVEC (orig, i); |
---|
| 412 | if (XVEC (orig, i) != NULL) |
---|
| 413 | { |
---|
| 414 | XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); |
---|
| 415 | for (j = 0; j < XVECLEN (copy, i); j++) |
---|
| 416 | XVECEXP (copy, i, j) |
---|
| 417 | = copy_most_rtx (XVECEXP (orig, i, j), may_share); |
---|
| 418 | } |
---|
| 419 | break; |
---|
| 420 | |
---|
| 421 | case 'w': |
---|
| 422 | XWINT (copy, i) = XWINT (orig, i); |
---|
| 423 | break; |
---|
| 424 | |
---|
| 425 | case 'n': |
---|
| 426 | case 'i': |
---|
| 427 | XINT (copy, i) = XINT (orig, i); |
---|
| 428 | break; |
---|
| 429 | |
---|
| 430 | case 's': |
---|
| 431 | case 'S': |
---|
| 432 | XSTR (copy, i) = XSTR (orig, i); |
---|
| 433 | break; |
---|
| 434 | |
---|
| 435 | default: |
---|
| 436 | abort (); |
---|
| 437 | } |
---|
| 438 | } |
---|
| 439 | return copy; |
---|
| 440 | } |
---|
| 441 | |
---|
| 442 | /* Subroutines of read_rtx. */ |
---|
| 443 | |
---|
| 444 | /* Dump code after printing a message. Used when read_rtx finds |
---|
| 445 | invalid data. */ |
---|
| 446 | |
---|
| 447 | static void |
---|
| 448 | dump_and_abort (expected_c, actual_c, infile) |
---|
| 449 | int expected_c, actual_c; |
---|
| 450 | FILE *infile; |
---|
| 451 | { |
---|
| 452 | int c, i; |
---|
| 453 | |
---|
| 454 | if (expected_c >= 0) |
---|
| 455 | fprintf (stderr, |
---|
| 456 | "Expected character %c. Found character %c.", |
---|
| 457 | expected_c, actual_c); |
---|
| 458 | fprintf (stderr, " At file position: %ld\n", ftell (infile)); |
---|
| 459 | fprintf (stderr, "Following characters are:\n\t"); |
---|
| 460 | for (i = 0; i < 200; i++) |
---|
| 461 | { |
---|
| 462 | c = getc (infile); |
---|
| 463 | if (EOF == c) break; |
---|
| 464 | putc (c, stderr); |
---|
| 465 | } |
---|
| 466 | fprintf (stderr, "Aborting.\n"); |
---|
| 467 | abort (); |
---|
| 468 | } |
---|
| 469 | |
---|
| 470 | /* Read chars from INFILE until a non-whitespace char |
---|
| 471 | and return that. Comments, both Lisp style and C style, |
---|
| 472 | are treated as whitespace. |
---|
| 473 | Tools such as genflags use this function. */ |
---|
| 474 | |
---|
| 475 | int |
---|
| 476 | read_skip_spaces (infile) |
---|
| 477 | FILE *infile; |
---|
| 478 | { |
---|
| 479 | register int c; |
---|
| 480 | while (c = getc (infile)) |
---|
| 481 | { |
---|
| 482 | if (c == ' ' || c == '\n' || c == '\t' || c == '\f') |
---|
| 483 | ; |
---|
| 484 | else if (c == ';') |
---|
| 485 | { |
---|
| 486 | while ((c = getc (infile)) && c != '\n') ; |
---|
| 487 | } |
---|
| 488 | else if (c == '/') |
---|
| 489 | { |
---|
| 490 | register int prevc; |
---|
| 491 | c = getc (infile); |
---|
| 492 | if (c != '*') |
---|
| 493 | dump_and_abort ('*', c, infile); |
---|
| 494 | |
---|
| 495 | prevc = 0; |
---|
| 496 | while (c = getc (infile)) |
---|
| 497 | { |
---|
| 498 | if (prevc == '*' && c == '/') |
---|
| 499 | break; |
---|
| 500 | prevc = c; |
---|
| 501 | } |
---|
| 502 | } |
---|
| 503 | else break; |
---|
| 504 | } |
---|
| 505 | return c; |
---|
| 506 | } |
---|
| 507 | |
---|
| 508 | /* Read an rtx code name into the buffer STR[]. |
---|
| 509 | It is terminated by any of the punctuation chars of rtx printed syntax. */ |
---|
| 510 | |
---|
| 511 | static void |
---|
| 512 | read_name (str, infile) |
---|
| 513 | char *str; |
---|
| 514 | FILE *infile; |
---|
| 515 | { |
---|
| 516 | register char *p; |
---|
| 517 | register int c; |
---|
| 518 | |
---|
| 519 | c = read_skip_spaces(infile); |
---|
| 520 | |
---|
| 521 | p = str; |
---|
| 522 | while (1) |
---|
| 523 | { |
---|
| 524 | if (c == ' ' || c == '\n' || c == '\t' || c == '\f') |
---|
| 525 | break; |
---|
| 526 | if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/' |
---|
| 527 | || c == '(' || c == '[') |
---|
| 528 | { |
---|
| 529 | ungetc (c, infile); |
---|
| 530 | break; |
---|
| 531 | } |
---|
| 532 | *p++ = c; |
---|
| 533 | c = getc (infile); |
---|
| 534 | } |
---|
| 535 | if (p == str) |
---|
| 536 | { |
---|
| 537 | fprintf (stderr, "missing name or number"); |
---|
| 538 | dump_and_abort (-1, -1, infile); |
---|
| 539 | } |
---|
| 540 | |
---|
| 541 | *p = 0; |
---|
| 542 | } |
---|
| 543 | |
---|
| 544 | /* Read an rtx in printed representation from INFILE |
---|
| 545 | and return an actual rtx in core constructed accordingly. |
---|
| 546 | read_rtx is not used in the compiler proper, but rather in |
---|
| 547 | the utilities gen*.c that construct C code from machine descriptions. */ |
---|
| 548 | |
---|
| 549 | rtx |
---|
| 550 | read_rtx (infile) |
---|
| 551 | FILE *infile; |
---|
| 552 | { |
---|
| 553 | register int i, j, list_counter; |
---|
| 554 | RTX_CODE tmp_code; |
---|
| 555 | register char *format_ptr; |
---|
| 556 | /* tmp_char is a buffer used for reading decimal integers |
---|
| 557 | and names of rtx types and machine modes. |
---|
| 558 | Therefore, 256 must be enough. */ |
---|
| 559 | char tmp_char[256]; |
---|
| 560 | rtx return_rtx; |
---|
| 561 | register int c; |
---|
| 562 | int tmp_int; |
---|
| 563 | HOST_WIDE_INT tmp_wide; |
---|
| 564 | |
---|
| 565 | /* Linked list structure for making RTXs: */ |
---|
| 566 | struct rtx_list |
---|
| 567 | { |
---|
| 568 | struct rtx_list *next; |
---|
| 569 | rtx value; /* Value of this node... */ |
---|
| 570 | }; |
---|
| 571 | |
---|
| 572 | c = read_skip_spaces (infile); /* Should be open paren. */ |
---|
| 573 | if (c != '(') |
---|
| 574 | dump_and_abort ('(', c, infile); |
---|
| 575 | |
---|
| 576 | read_name (tmp_char, infile); |
---|
| 577 | |
---|
| 578 | tmp_code = UNKNOWN; |
---|
| 579 | |
---|
| 580 | for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */ |
---|
| 581 | { |
---|
| 582 | if (!(strcmp (tmp_char, GET_RTX_NAME (i)))) |
---|
| 583 | { |
---|
| 584 | tmp_code = (RTX_CODE) i; /* get value for name */ |
---|
| 585 | break; |
---|
| 586 | } |
---|
| 587 | } |
---|
| 588 | if (tmp_code == UNKNOWN) |
---|
| 589 | { |
---|
| 590 | fprintf (stderr, |
---|
| 591 | "Unknown rtx read in rtl.read_rtx(). Code name was %s .", |
---|
| 592 | tmp_char); |
---|
| 593 | } |
---|
| 594 | /* (NIL) stands for an expression that isn't there. */ |
---|
| 595 | if (tmp_code == NIL) |
---|
| 596 | { |
---|
| 597 | /* Discard the closeparen. */ |
---|
| 598 | while ((c = getc (infile)) && c != ')'); |
---|
| 599 | return 0; |
---|
| 600 | } |
---|
| 601 | |
---|
| 602 | return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression |
---|
| 603 | then we free this space below. */ |
---|
| 604 | format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx)); |
---|
| 605 | |
---|
| 606 | /* If what follows is `: mode ', read it and |
---|
| 607 | store the mode in the rtx. */ |
---|
| 608 | |
---|
| 609 | i = read_skip_spaces (infile); |
---|
| 610 | if (i == ':') |
---|
| 611 | { |
---|
| 612 | register int k; |
---|
| 613 | read_name (tmp_char, infile); |
---|
| 614 | for (k = 0; k < NUM_MACHINE_MODES; k++) |
---|
| 615 | if (!strcmp (GET_MODE_NAME (k), tmp_char)) |
---|
| 616 | break; |
---|
| 617 | |
---|
| 618 | PUT_MODE (return_rtx, (enum machine_mode) k ); |
---|
| 619 | } |
---|
| 620 | else |
---|
| 621 | ungetc (i, infile); |
---|
| 622 | |
---|
| 623 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++) |
---|
| 624 | switch (*format_ptr++) |
---|
| 625 | { |
---|
| 626 | /* 0 means a field for internal use only. |
---|
| 627 | Don't expect it to be present in the input. */ |
---|
| 628 | case '0': |
---|
| 629 | break; |
---|
| 630 | |
---|
| 631 | case 'e': |
---|
| 632 | case 'u': |
---|
| 633 | XEXP (return_rtx, i) = read_rtx (infile); |
---|
| 634 | break; |
---|
| 635 | |
---|
| 636 | case 'V': |
---|
| 637 | /* 'V' is an optional vector: if a closeparen follows, |
---|
| 638 | just store NULL for this element. */ |
---|
| 639 | c = read_skip_spaces (infile); |
---|
| 640 | ungetc (c, infile); |
---|
| 641 | if (c == ')') |
---|
| 642 | { |
---|
| 643 | XVEC (return_rtx, i) = 0; |
---|
| 644 | break; |
---|
| 645 | } |
---|
| 646 | /* Now process the vector. */ |
---|
| 647 | |
---|
| 648 | case 'E': |
---|
| 649 | { |
---|
| 650 | register struct rtx_list *next_rtx, *rtx_list_link; |
---|
| 651 | struct rtx_list *list_rtx; |
---|
| 652 | |
---|
| 653 | c = read_skip_spaces (infile); |
---|
| 654 | if (c != '[') |
---|
| 655 | dump_and_abort ('[', c, infile); |
---|
| 656 | |
---|
| 657 | /* add expressions to a list, while keeping a count */ |
---|
| 658 | next_rtx = NULL; |
---|
| 659 | list_counter = 0; |
---|
| 660 | while ((c = read_skip_spaces (infile)) && c != ']') |
---|
| 661 | { |
---|
| 662 | ungetc (c, infile); |
---|
| 663 | list_counter++; |
---|
| 664 | rtx_list_link = (struct rtx_list *) |
---|
| 665 | alloca (sizeof (struct rtx_list)); |
---|
| 666 | rtx_list_link->value = read_rtx (infile); |
---|
| 667 | if (next_rtx == 0) |
---|
| 668 | list_rtx = rtx_list_link; |
---|
| 669 | else |
---|
| 670 | next_rtx->next = rtx_list_link; |
---|
| 671 | next_rtx = rtx_list_link; |
---|
| 672 | rtx_list_link->next = 0; |
---|
| 673 | } |
---|
| 674 | /* get vector length and allocate it */ |
---|
| 675 | XVEC (return_rtx, i) = (list_counter |
---|
| 676 | ? rtvec_alloc (list_counter) : NULL_RTVEC); |
---|
| 677 | if (list_counter > 0) |
---|
| 678 | { |
---|
| 679 | next_rtx = list_rtx; |
---|
| 680 | for (j = 0; j < list_counter; j++, |
---|
| 681 | next_rtx = next_rtx->next) |
---|
| 682 | XVECEXP (return_rtx, i, j) = next_rtx->value; |
---|
| 683 | } |
---|
| 684 | /* close bracket gotten */ |
---|
| 685 | } |
---|
| 686 | break; |
---|
| 687 | |
---|
| 688 | case 'S': |
---|
| 689 | /* 'S' is an optional string: if a closeparen follows, |
---|
| 690 | just store NULL for this element. */ |
---|
| 691 | c = read_skip_spaces (infile); |
---|
| 692 | ungetc (c, infile); |
---|
| 693 | if (c == ')') |
---|
| 694 | { |
---|
| 695 | XSTR (return_rtx, i) = 0; |
---|
| 696 | break; |
---|
| 697 | } |
---|
| 698 | |
---|
| 699 | case 's': |
---|
| 700 | { |
---|
| 701 | int saw_paren = 0; |
---|
| 702 | register char *stringbuf; |
---|
| 703 | |
---|
| 704 | c = read_skip_spaces (infile); |
---|
| 705 | if (c == '(') |
---|
| 706 | { |
---|
| 707 | saw_paren = 1; |
---|
| 708 | c = read_skip_spaces (infile); |
---|
| 709 | } |
---|
| 710 | if (c != '"') |
---|
| 711 | dump_and_abort ('"', c, infile); |
---|
| 712 | |
---|
| 713 | while (1) |
---|
| 714 | { |
---|
| 715 | c = getc (infile); /* Read the string */ |
---|
| 716 | if (c == '\\') |
---|
| 717 | { |
---|
| 718 | c = getc (infile); /* Read the string */ |
---|
| 719 | /* \; makes stuff for a C string constant containing |
---|
| 720 | newline and tab. */ |
---|
| 721 | if (c == ';') |
---|
| 722 | { |
---|
| 723 | obstack_grow (rtl_obstack, "\\n\\t", 4); |
---|
| 724 | continue; |
---|
| 725 | } |
---|
| 726 | } |
---|
| 727 | else if (c == '"') |
---|
| 728 | break; |
---|
| 729 | |
---|
| 730 | obstack_1grow (rtl_obstack, c); |
---|
| 731 | } |
---|
| 732 | |
---|
| 733 | obstack_1grow (rtl_obstack, 0); |
---|
| 734 | stringbuf = (char *) obstack_finish (rtl_obstack); |
---|
| 735 | |
---|
| 736 | if (saw_paren) |
---|
| 737 | { |
---|
| 738 | c = read_skip_spaces (infile); |
---|
| 739 | if (c != ')') |
---|
| 740 | dump_and_abort (')', c, infile); |
---|
| 741 | } |
---|
| 742 | XSTR (return_rtx, i) = stringbuf; |
---|
| 743 | } |
---|
| 744 | break; |
---|
| 745 | |
---|
| 746 | case 'w': |
---|
| 747 | read_name (tmp_char, infile); |
---|
| 748 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT |
---|
| 749 | tmp_wide = atoi (tmp_char); |
---|
| 750 | #else |
---|
| 751 | tmp_wide = atol (tmp_char); |
---|
| 752 | #endif |
---|
| 753 | XWINT (return_rtx, i) = tmp_wide; |
---|
| 754 | break; |
---|
| 755 | |
---|
| 756 | case 'i': |
---|
| 757 | case 'n': |
---|
| 758 | read_name (tmp_char, infile); |
---|
| 759 | tmp_int = atoi (tmp_char); |
---|
| 760 | XINT (return_rtx, i) = tmp_int; |
---|
| 761 | break; |
---|
| 762 | |
---|
| 763 | default: |
---|
| 764 | fprintf (stderr, |
---|
| 765 | "switch format wrong in rtl.read_rtx(). format was: %c.\n", |
---|
| 766 | format_ptr[-1]); |
---|
| 767 | fprintf (stderr, "\tfile position: %ld\n", ftell (infile)); |
---|
| 768 | abort (); |
---|
| 769 | } |
---|
| 770 | |
---|
| 771 | c = read_skip_spaces (infile); |
---|
| 772 | if (c != ')') |
---|
| 773 | dump_and_abort (')', c, infile); |
---|
| 774 | |
---|
| 775 | return return_rtx; |
---|
| 776 | } |
---|
| 777 | |
---|
| 778 | /* This is called once per compilation, before any rtx's are constructed. |
---|
| 779 | It initializes the vector `rtx_length', the extra CC modes, if any, |
---|
| 780 | and computes certain commonly-used modes. */ |
---|
| 781 | |
---|
| 782 | void |
---|
| 783 | init_rtl () |
---|
| 784 | { |
---|
| 785 | int min_class_size[(int) MAX_MODE_CLASS]; |
---|
| 786 | enum machine_mode mode; |
---|
| 787 | int i; |
---|
| 788 | |
---|
| 789 | for (i = 0; i < NUM_RTX_CODE; i++) |
---|
| 790 | rtx_length[i] = strlen (rtx_format[i]); |
---|
| 791 | |
---|
| 792 | /* Make CONST_DOUBLE bigger, if real values are bigger than |
---|
| 793 | it normally expects to have room for. |
---|
| 794 | Note that REAL_VALUE_TYPE is not defined by default, |
---|
| 795 | since tree.h is not included. But the default dfn as `double' |
---|
| 796 | would do no harm. */ |
---|
| 797 | #ifdef REAL_VALUE_TYPE |
---|
| 798 | i = sizeof (REAL_VALUE_TYPE) / sizeof (rtunion) + 2; |
---|
| 799 | if (rtx_length[(int) CONST_DOUBLE] < i) |
---|
| 800 | { |
---|
| 801 | char *s = (char *) xmalloc (i + 1); |
---|
| 802 | rtx_length[(int) CONST_DOUBLE] = i; |
---|
| 803 | rtx_format[(int) CONST_DOUBLE] = s; |
---|
| 804 | *s++ = 'e'; |
---|
| 805 | *s++ = '0'; |
---|
| 806 | /* Set the GET_RTX_FORMAT of CONST_DOUBLE to a string |
---|
| 807 | of as many `w's as we now have elements. Subtract two from |
---|
| 808 | the size to account for the 'e' and the '0'. */ |
---|
| 809 | for (i = 2; i < rtx_length[(int) CONST_DOUBLE]; i++) |
---|
| 810 | *s++ = 'w'; |
---|
| 811 | *s++ = 0; |
---|
| 812 | } |
---|
| 813 | #endif |
---|
| 814 | |
---|
| 815 | #ifdef EXTRA_CC_MODES |
---|
| 816 | for (i = (int) CCmode + 1; i < (int) MAX_MACHINE_MODE; i++) |
---|
| 817 | { |
---|
| 818 | mode_class[i] = MODE_CC; |
---|
| 819 | mode_size[i] = mode_size[(int) CCmode]; |
---|
| 820 | mode_unit_size[i] = mode_unit_size[(int) CCmode]; |
---|
| 821 | mode_wider_mode[i - 1] = (enum machine_mode) i; |
---|
| 822 | mode_wider_mode[i] = VOIDmode; |
---|
| 823 | } |
---|
| 824 | #endif |
---|
| 825 | |
---|
| 826 | /* Find the narrowest mode for each class. */ |
---|
| 827 | |
---|
| 828 | for (i = 0; i < (int) MAX_MODE_CLASS; i++) |
---|
| 829 | min_class_size[i] = 1000; |
---|
| 830 | |
---|
| 831 | for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; |
---|
| 832 | mode = (enum machine_mode) ((int) mode + 1)) |
---|
| 833 | { |
---|
| 834 | if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)]) |
---|
| 835 | { |
---|
| 836 | class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode; |
---|
| 837 | min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode); |
---|
| 838 | } |
---|
| 839 | } |
---|
| 840 | } |
---|
| 841 | |
---|
| 842 | #ifdef memset |
---|
| 843 | gcc_memset (dest, value, len) |
---|
| 844 | char *dest; |
---|
| 845 | int value; |
---|
| 846 | int len; |
---|
| 847 | { |
---|
| 848 | while (len-- > 0) |
---|
| 849 | *dest++ = value; |
---|
| 850 | } |
---|
| 851 | #endif /* memset */ |
---|