1 | /* Allocate and read RTL for GNU C Compiler. |
---|
2 | Copyright (C) 1987, 1988, 1991, 1994, 1997 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 | "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END", |
---|
177 | "NOTE_REPEATED_LINE_NUMBER" }; |
---|
178 | |
---|
179 | char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0", |
---|
180 | "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL", |
---|
181 | "REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED", |
---|
182 | "REG_CC_SETTER", "REG_CC_USER", "REG_LABEL", |
---|
183 | "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB", |
---|
184 | "REG_EXEC_COUNT" }; |
---|
185 | |
---|
186 | static void dump_and_abort PROTO((int, int, FILE *)); |
---|
187 | static void read_name PROTO((char *, FILE *)); |
---|
188 | |
---|
189 | /* Allocate an rtx vector of N elements. |
---|
190 | Store the length, and initialize all elements to zero. */ |
---|
191 | |
---|
192 | rtvec |
---|
193 | rtvec_alloc (n) |
---|
194 | int n; |
---|
195 | { |
---|
196 | rtvec rt; |
---|
197 | int i; |
---|
198 | |
---|
199 | rt = (rtvec) obstack_alloc (rtl_obstack, |
---|
200 | sizeof (struct rtvec_def) |
---|
201 | + (( n - 1) * sizeof (rtunion))); |
---|
202 | |
---|
203 | /* clear out the vector */ |
---|
204 | PUT_NUM_ELEM (rt, n); |
---|
205 | |
---|
206 | for (i = 0; i < n; i++) |
---|
207 | rt->elem[i].rtwint = 0; |
---|
208 | |
---|
209 | return rt; |
---|
210 | } |
---|
211 | |
---|
212 | /* Allocate an rtx of code CODE. The CODE is stored in the rtx; |
---|
213 | all the rest is initialized to zero. */ |
---|
214 | |
---|
215 | rtx |
---|
216 | rtx_alloc (code) |
---|
217 | RTX_CODE code; |
---|
218 | { |
---|
219 | rtx rt; |
---|
220 | register struct obstack *ob = rtl_obstack; |
---|
221 | register int nelts = GET_RTX_LENGTH (code); |
---|
222 | register int length = sizeof (struct rtx_def) |
---|
223 | + (nelts - 1) * sizeof (rtunion); |
---|
224 | |
---|
225 | /* This function is called more than any other in GCC, |
---|
226 | so we manipulate the obstack directly. |
---|
227 | |
---|
228 | Even though rtx objects are word aligned, we may be sharing an obstack |
---|
229 | with tree nodes, which may have to be double-word aligned. So align |
---|
230 | our length to the alignment mask in the obstack. */ |
---|
231 | |
---|
232 | length = (length + ob->alignment_mask) & ~ ob->alignment_mask; |
---|
233 | |
---|
234 | if (ob->chunk_limit - ob->next_free < length) |
---|
235 | _obstack_newchunk (ob, length); |
---|
236 | rt = (rtx)ob->object_base; |
---|
237 | ob->next_free += length; |
---|
238 | ob->object_base = ob->next_free; |
---|
239 | |
---|
240 | /* We want to clear everything up to the FLD array. Normally, this is |
---|
241 | one int, but we don't want to assume that and it isn't very portable |
---|
242 | anyway; this is. */ |
---|
243 | |
---|
244 | length = (sizeof (struct rtx_def) - sizeof (rtunion) - 1) / sizeof (int); |
---|
245 | for (; length >= 0; length--) |
---|
246 | ((int *) rt)[length] = 0; |
---|
247 | |
---|
248 | PUT_CODE (rt, code); |
---|
249 | |
---|
250 | return rt; |
---|
251 | } |
---|
252 | |
---|
253 | /* Free the rtx X and all RTL allocated since X. */ |
---|
254 | |
---|
255 | void |
---|
256 | rtx_free (x) |
---|
257 | rtx x; |
---|
258 | { |
---|
259 | obstack_free (rtl_obstack, x); |
---|
260 | } |
---|
261 | |
---|
262 | /* Create a new copy of an rtx. |
---|
263 | Recursively copies the operands of the rtx, |
---|
264 | except for those few rtx codes that are sharable. */ |
---|
265 | |
---|
266 | rtx |
---|
267 | copy_rtx (orig) |
---|
268 | register rtx orig; |
---|
269 | { |
---|
270 | register rtx copy; |
---|
271 | register int i, j; |
---|
272 | register RTX_CODE code; |
---|
273 | register char *format_ptr; |
---|
274 | |
---|
275 | code = GET_CODE (orig); |
---|
276 | |
---|
277 | switch (code) |
---|
278 | { |
---|
279 | case REG: |
---|
280 | case QUEUED: |
---|
281 | case CONST_INT: |
---|
282 | case CONST_DOUBLE: |
---|
283 | case SYMBOL_REF: |
---|
284 | case CODE_LABEL: |
---|
285 | case PC: |
---|
286 | case CC0: |
---|
287 | case SCRATCH: |
---|
288 | /* SCRATCH must be shared because they represent distinct values. */ |
---|
289 | case ADDRESSOF: |
---|
290 | return orig; |
---|
291 | |
---|
292 | case CONST: |
---|
293 | /* CONST can be shared if it contains a SYMBOL_REF. If it contains |
---|
294 | a LABEL_REF, it isn't sharable. */ |
---|
295 | if (GET_CODE (XEXP (orig, 0)) == PLUS |
---|
296 | && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF |
---|
297 | && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT) |
---|
298 | return orig; |
---|
299 | break; |
---|
300 | |
---|
301 | /* A MEM with a constant address is not sharable. The problem is that |
---|
302 | the constant address may need to be reloaded. If the mem is shared, |
---|
303 | then reloading one copy of this mem will cause all copies to appear |
---|
304 | to have been reloaded. */ |
---|
305 | |
---|
306 | default: |
---|
307 | break; |
---|
308 | } |
---|
309 | |
---|
310 | copy = rtx_alloc (code); |
---|
311 | PUT_MODE (copy, GET_MODE (orig)); |
---|
312 | copy->in_struct = orig->in_struct; |
---|
313 | copy->volatil = orig->volatil; |
---|
314 | copy->unchanging = orig->unchanging; |
---|
315 | copy->integrated = orig->integrated; |
---|
316 | |
---|
317 | format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); |
---|
318 | |
---|
319 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) |
---|
320 | { |
---|
321 | switch (*format_ptr++) |
---|
322 | { |
---|
323 | case 'e': |
---|
324 | XEXP (copy, i) = XEXP (orig, i); |
---|
325 | if (XEXP (orig, i) != NULL) |
---|
326 | XEXP (copy, i) = copy_rtx (XEXP (orig, i)); |
---|
327 | break; |
---|
328 | |
---|
329 | case '0': |
---|
330 | case 'u': |
---|
331 | XEXP (copy, i) = XEXP (orig, i); |
---|
332 | break; |
---|
333 | |
---|
334 | case 'E': |
---|
335 | case 'V': |
---|
336 | XVEC (copy, i) = XVEC (orig, i); |
---|
337 | if (XVEC (orig, i) != NULL) |
---|
338 | { |
---|
339 | XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); |
---|
340 | for (j = 0; j < XVECLEN (copy, i); j++) |
---|
341 | XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j)); |
---|
342 | } |
---|
343 | break; |
---|
344 | |
---|
345 | case 'w': |
---|
346 | XWINT (copy, i) = XWINT (orig, i); |
---|
347 | break; |
---|
348 | |
---|
349 | case 'i': |
---|
350 | XINT (copy, i) = XINT (orig, i); |
---|
351 | break; |
---|
352 | |
---|
353 | case 's': |
---|
354 | case 'S': |
---|
355 | XSTR (copy, i) = XSTR (orig, i); |
---|
356 | break; |
---|
357 | |
---|
358 | default: |
---|
359 | abort (); |
---|
360 | } |
---|
361 | } |
---|
362 | return copy; |
---|
363 | } |
---|
364 | |
---|
365 | /* Similar to `copy_rtx' except that if MAY_SHARE is present, it is |
---|
366 | placed in the result directly, rather than being copied. */ |
---|
367 | |
---|
368 | rtx |
---|
369 | copy_most_rtx (orig, may_share) |
---|
370 | register rtx orig; |
---|
371 | register rtx may_share; |
---|
372 | { |
---|
373 | register rtx copy; |
---|
374 | register int i, j; |
---|
375 | register RTX_CODE code; |
---|
376 | register char *format_ptr; |
---|
377 | |
---|
378 | if (orig == may_share) |
---|
379 | return orig; |
---|
380 | |
---|
381 | code = GET_CODE (orig); |
---|
382 | |
---|
383 | switch (code) |
---|
384 | { |
---|
385 | case REG: |
---|
386 | case QUEUED: |
---|
387 | case CONST_INT: |
---|
388 | case CONST_DOUBLE: |
---|
389 | case SYMBOL_REF: |
---|
390 | case CODE_LABEL: |
---|
391 | case PC: |
---|
392 | case CC0: |
---|
393 | return orig; |
---|
394 | default: |
---|
395 | break; |
---|
396 | } |
---|
397 | |
---|
398 | copy = rtx_alloc (code); |
---|
399 | PUT_MODE (copy, GET_MODE (orig)); |
---|
400 | copy->in_struct = orig->in_struct; |
---|
401 | copy->volatil = orig->volatil; |
---|
402 | copy->unchanging = orig->unchanging; |
---|
403 | copy->integrated = orig->integrated; |
---|
404 | |
---|
405 | format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); |
---|
406 | |
---|
407 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) |
---|
408 | { |
---|
409 | switch (*format_ptr++) |
---|
410 | { |
---|
411 | case 'e': |
---|
412 | XEXP (copy, i) = XEXP (orig, i); |
---|
413 | if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share) |
---|
414 | XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share); |
---|
415 | break; |
---|
416 | |
---|
417 | case '0': |
---|
418 | case 'u': |
---|
419 | XEXP (copy, i) = XEXP (orig, i); |
---|
420 | break; |
---|
421 | |
---|
422 | case 'E': |
---|
423 | case 'V': |
---|
424 | XVEC (copy, i) = XVEC (orig, i); |
---|
425 | if (XVEC (orig, i) != NULL) |
---|
426 | { |
---|
427 | XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); |
---|
428 | for (j = 0; j < XVECLEN (copy, i); j++) |
---|
429 | XVECEXP (copy, i, j) |
---|
430 | = copy_most_rtx (XVECEXP (orig, i, j), may_share); |
---|
431 | } |
---|
432 | break; |
---|
433 | |
---|
434 | case 'w': |
---|
435 | XWINT (copy, i) = XWINT (orig, i); |
---|
436 | break; |
---|
437 | |
---|
438 | case 'n': |
---|
439 | case 'i': |
---|
440 | XINT (copy, i) = XINT (orig, i); |
---|
441 | break; |
---|
442 | |
---|
443 | case 's': |
---|
444 | case 'S': |
---|
445 | XSTR (copy, i) = XSTR (orig, i); |
---|
446 | break; |
---|
447 | |
---|
448 | default: |
---|
449 | abort (); |
---|
450 | } |
---|
451 | } |
---|
452 | return copy; |
---|
453 | } |
---|
454 | |
---|
455 | /* Subroutines of read_rtx. */ |
---|
456 | |
---|
457 | /* Dump code after printing a message. Used when read_rtx finds |
---|
458 | invalid data. */ |
---|
459 | |
---|
460 | static void |
---|
461 | dump_and_abort (expected_c, actual_c, infile) |
---|
462 | int expected_c, actual_c; |
---|
463 | FILE *infile; |
---|
464 | { |
---|
465 | int c, i; |
---|
466 | |
---|
467 | if (expected_c >= 0) |
---|
468 | fprintf (stderr, |
---|
469 | "Expected character %c. Found character %c.", |
---|
470 | expected_c, actual_c); |
---|
471 | fprintf (stderr, " At file position: %ld\n", ftell (infile)); |
---|
472 | fprintf (stderr, "Following characters are:\n\t"); |
---|
473 | for (i = 0; i < 200; i++) |
---|
474 | { |
---|
475 | c = getc (infile); |
---|
476 | if (EOF == c) break; |
---|
477 | putc (c, stderr); |
---|
478 | } |
---|
479 | fprintf (stderr, "Aborting.\n"); |
---|
480 | abort (); |
---|
481 | } |
---|
482 | |
---|
483 | /* Read chars from INFILE until a non-whitespace char |
---|
484 | and return that. Comments, both Lisp style and C style, |
---|
485 | are treated as whitespace. |
---|
486 | Tools such as genflags use this function. */ |
---|
487 | |
---|
488 | int |
---|
489 | read_skip_spaces (infile) |
---|
490 | FILE *infile; |
---|
491 | { |
---|
492 | register int c; |
---|
493 | while (c = getc (infile)) |
---|
494 | { |
---|
495 | if (c == ' ' || c == '\n' || c == '\t' || c == '\f') |
---|
496 | ; |
---|
497 | else if (c == ';') |
---|
498 | { |
---|
499 | while ((c = getc (infile)) && c != '\n') ; |
---|
500 | } |
---|
501 | else if (c == '/') |
---|
502 | { |
---|
503 | register int prevc; |
---|
504 | c = getc (infile); |
---|
505 | if (c != '*') |
---|
506 | dump_and_abort ('*', c, infile); |
---|
507 | |
---|
508 | prevc = 0; |
---|
509 | while (c = getc (infile)) |
---|
510 | { |
---|
511 | if (prevc == '*' && c == '/') |
---|
512 | break; |
---|
513 | prevc = c; |
---|
514 | } |
---|
515 | } |
---|
516 | else break; |
---|
517 | } |
---|
518 | return c; |
---|
519 | } |
---|
520 | |
---|
521 | /* Read an rtx code name into the buffer STR[]. |
---|
522 | It is terminated by any of the punctuation chars of rtx printed syntax. */ |
---|
523 | |
---|
524 | static void |
---|
525 | read_name (str, infile) |
---|
526 | char *str; |
---|
527 | FILE *infile; |
---|
528 | { |
---|
529 | register char *p; |
---|
530 | register int c; |
---|
531 | |
---|
532 | c = read_skip_spaces(infile); |
---|
533 | |
---|
534 | p = str; |
---|
535 | while (1) |
---|
536 | { |
---|
537 | if (c == ' ' || c == '\n' || c == '\t' || c == '\f') |
---|
538 | break; |
---|
539 | if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/' |
---|
540 | || c == '(' || c == '[') |
---|
541 | { |
---|
542 | ungetc (c, infile); |
---|
543 | break; |
---|
544 | } |
---|
545 | *p++ = c; |
---|
546 | c = getc (infile); |
---|
547 | } |
---|
548 | if (p == str) |
---|
549 | { |
---|
550 | fprintf (stderr, "missing name or number"); |
---|
551 | dump_and_abort (-1, -1, infile); |
---|
552 | } |
---|
553 | |
---|
554 | *p = 0; |
---|
555 | } |
---|
556 | |
---|
557 | /* Read an rtx in printed representation from INFILE |
---|
558 | and return an actual rtx in core constructed accordingly. |
---|
559 | read_rtx is not used in the compiler proper, but rather in |
---|
560 | the utilities gen*.c that construct C code from machine descriptions. */ |
---|
561 | |
---|
562 | rtx |
---|
563 | read_rtx (infile) |
---|
564 | FILE *infile; |
---|
565 | { |
---|
566 | register int i, j, list_counter; |
---|
567 | RTX_CODE tmp_code; |
---|
568 | register char *format_ptr; |
---|
569 | /* tmp_char is a buffer used for reading decimal integers |
---|
570 | and names of rtx types and machine modes. |
---|
571 | Therefore, 256 must be enough. */ |
---|
572 | char tmp_char[256]; |
---|
573 | rtx return_rtx; |
---|
574 | register int c; |
---|
575 | int tmp_int; |
---|
576 | HOST_WIDE_INT tmp_wide; |
---|
577 | |
---|
578 | /* Linked list structure for making RTXs: */ |
---|
579 | struct rtx_list |
---|
580 | { |
---|
581 | struct rtx_list *next; |
---|
582 | rtx value; /* Value of this node... */ |
---|
583 | }; |
---|
584 | |
---|
585 | c = read_skip_spaces (infile); /* Should be open paren. */ |
---|
586 | if (c != '(') |
---|
587 | dump_and_abort ('(', c, infile); |
---|
588 | |
---|
589 | read_name (tmp_char, infile); |
---|
590 | |
---|
591 | tmp_code = UNKNOWN; |
---|
592 | |
---|
593 | for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */ |
---|
594 | { |
---|
595 | if (!(strcmp (tmp_char, GET_RTX_NAME (i)))) |
---|
596 | { |
---|
597 | tmp_code = (RTX_CODE) i; /* get value for name */ |
---|
598 | break; |
---|
599 | } |
---|
600 | } |
---|
601 | if (tmp_code == UNKNOWN) |
---|
602 | { |
---|
603 | fprintf (stderr, |
---|
604 | "Unknown rtx read in rtl.read_rtx(). Code name was %s .", |
---|
605 | tmp_char); |
---|
606 | } |
---|
607 | /* (NIL) stands for an expression that isn't there. */ |
---|
608 | if (tmp_code == NIL) |
---|
609 | { |
---|
610 | /* Discard the closeparen. */ |
---|
611 | while ((c = getc (infile)) && c != ')'); |
---|
612 | return 0; |
---|
613 | } |
---|
614 | |
---|
615 | return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression |
---|
616 | then we free this space below. */ |
---|
617 | format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx)); |
---|
618 | |
---|
619 | /* If what follows is `: mode ', read it and |
---|
620 | store the mode in the rtx. */ |
---|
621 | |
---|
622 | i = read_skip_spaces (infile); |
---|
623 | if (i == ':') |
---|
624 | { |
---|
625 | register int k; |
---|
626 | read_name (tmp_char, infile); |
---|
627 | for (k = 0; k < NUM_MACHINE_MODES; k++) |
---|
628 | if (!strcmp (GET_MODE_NAME (k), tmp_char)) |
---|
629 | break; |
---|
630 | |
---|
631 | PUT_MODE (return_rtx, (enum machine_mode) k ); |
---|
632 | } |
---|
633 | else |
---|
634 | ungetc (i, infile); |
---|
635 | |
---|
636 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++) |
---|
637 | switch (*format_ptr++) |
---|
638 | { |
---|
639 | /* 0 means a field for internal use only. |
---|
640 | Don't expect it to be present in the input. */ |
---|
641 | case '0': |
---|
642 | break; |
---|
643 | |
---|
644 | case 'e': |
---|
645 | case 'u': |
---|
646 | XEXP (return_rtx, i) = read_rtx (infile); |
---|
647 | break; |
---|
648 | |
---|
649 | case 'V': |
---|
650 | /* 'V' is an optional vector: if a closeparen follows, |
---|
651 | just store NULL for this element. */ |
---|
652 | c = read_skip_spaces (infile); |
---|
653 | ungetc (c, infile); |
---|
654 | if (c == ')') |
---|
655 | { |
---|
656 | XVEC (return_rtx, i) = 0; |
---|
657 | break; |
---|
658 | } |
---|
659 | /* Now process the vector. */ |
---|
660 | |
---|
661 | case 'E': |
---|
662 | { |
---|
663 | register struct rtx_list *next_rtx, *rtx_list_link; |
---|
664 | struct rtx_list *list_rtx; |
---|
665 | |
---|
666 | c = read_skip_spaces (infile); |
---|
667 | if (c != '[') |
---|
668 | dump_and_abort ('[', c, infile); |
---|
669 | |
---|
670 | /* add expressions to a list, while keeping a count */ |
---|
671 | next_rtx = NULL; |
---|
672 | list_counter = 0; |
---|
673 | while ((c = read_skip_spaces (infile)) && c != ']') |
---|
674 | { |
---|
675 | ungetc (c, infile); |
---|
676 | list_counter++; |
---|
677 | rtx_list_link = (struct rtx_list *) |
---|
678 | alloca (sizeof (struct rtx_list)); |
---|
679 | rtx_list_link->value = read_rtx (infile); |
---|
680 | if (next_rtx == 0) |
---|
681 | list_rtx = rtx_list_link; |
---|
682 | else |
---|
683 | next_rtx->next = rtx_list_link; |
---|
684 | next_rtx = rtx_list_link; |
---|
685 | rtx_list_link->next = 0; |
---|
686 | } |
---|
687 | /* get vector length and allocate it */ |
---|
688 | XVEC (return_rtx, i) = (list_counter |
---|
689 | ? rtvec_alloc (list_counter) : NULL_RTVEC); |
---|
690 | if (list_counter > 0) |
---|
691 | { |
---|
692 | next_rtx = list_rtx; |
---|
693 | for (j = 0; j < list_counter; j++, |
---|
694 | next_rtx = next_rtx->next) |
---|
695 | XVECEXP (return_rtx, i, j) = next_rtx->value; |
---|
696 | } |
---|
697 | /* close bracket gotten */ |
---|
698 | } |
---|
699 | break; |
---|
700 | |
---|
701 | case 'S': |
---|
702 | /* 'S' is an optional string: if a closeparen follows, |
---|
703 | just store NULL for this element. */ |
---|
704 | c = read_skip_spaces (infile); |
---|
705 | ungetc (c, infile); |
---|
706 | if (c == ')') |
---|
707 | { |
---|
708 | XSTR (return_rtx, i) = 0; |
---|
709 | break; |
---|
710 | } |
---|
711 | |
---|
712 | case 's': |
---|
713 | { |
---|
714 | int saw_paren = 0; |
---|
715 | register char *stringbuf; |
---|
716 | |
---|
717 | c = read_skip_spaces (infile); |
---|
718 | if (c == '(') |
---|
719 | { |
---|
720 | saw_paren = 1; |
---|
721 | c = read_skip_spaces (infile); |
---|
722 | } |
---|
723 | if (c != '"') |
---|
724 | dump_and_abort ('"', c, infile); |
---|
725 | |
---|
726 | while (1) |
---|
727 | { |
---|
728 | c = getc (infile); /* Read the string */ |
---|
729 | if (c == '\\') |
---|
730 | { |
---|
731 | c = getc (infile); /* Read the string */ |
---|
732 | /* \; makes stuff for a C string constant containing |
---|
733 | newline and tab. */ |
---|
734 | if (c == ';') |
---|
735 | { |
---|
736 | obstack_grow (rtl_obstack, "\\n\\t", 4); |
---|
737 | continue; |
---|
738 | } |
---|
739 | } |
---|
740 | else if (c == '"') |
---|
741 | break; |
---|
742 | |
---|
743 | obstack_1grow (rtl_obstack, c); |
---|
744 | } |
---|
745 | |
---|
746 | obstack_1grow (rtl_obstack, 0); |
---|
747 | stringbuf = (char *) obstack_finish (rtl_obstack); |
---|
748 | |
---|
749 | if (saw_paren) |
---|
750 | { |
---|
751 | c = read_skip_spaces (infile); |
---|
752 | if (c != ')') |
---|
753 | dump_and_abort (')', c, infile); |
---|
754 | } |
---|
755 | XSTR (return_rtx, i) = stringbuf; |
---|
756 | } |
---|
757 | break; |
---|
758 | |
---|
759 | case 'w': |
---|
760 | read_name (tmp_char, infile); |
---|
761 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT |
---|
762 | tmp_wide = atoi (tmp_char); |
---|
763 | #else |
---|
764 | tmp_wide = atol (tmp_char); |
---|
765 | #endif |
---|
766 | XWINT (return_rtx, i) = tmp_wide; |
---|
767 | break; |
---|
768 | |
---|
769 | case 'i': |
---|
770 | case 'n': |
---|
771 | read_name (tmp_char, infile); |
---|
772 | tmp_int = atoi (tmp_char); |
---|
773 | XINT (return_rtx, i) = tmp_int; |
---|
774 | break; |
---|
775 | |
---|
776 | default: |
---|
777 | fprintf (stderr, |
---|
778 | "switch format wrong in rtl.read_rtx(). format was: %c.\n", |
---|
779 | format_ptr[-1]); |
---|
780 | fprintf (stderr, "\tfile position: %ld\n", ftell (infile)); |
---|
781 | abort (); |
---|
782 | } |
---|
783 | |
---|
784 | c = read_skip_spaces (infile); |
---|
785 | if (c != ')') |
---|
786 | dump_and_abort (')', c, infile); |
---|
787 | |
---|
788 | return return_rtx; |
---|
789 | } |
---|
790 | |
---|
791 | /* This is called once per compilation, before any rtx's are constructed. |
---|
792 | It initializes the vector `rtx_length', the extra CC modes, if any, |
---|
793 | and computes certain commonly-used modes. */ |
---|
794 | |
---|
795 | void |
---|
796 | init_rtl () |
---|
797 | { |
---|
798 | int min_class_size[(int) MAX_MODE_CLASS]; |
---|
799 | enum machine_mode mode; |
---|
800 | int i; |
---|
801 | |
---|
802 | for (i = 0; i < NUM_RTX_CODE; i++) |
---|
803 | rtx_length[i] = strlen (rtx_format[i]); |
---|
804 | |
---|
805 | /* Make CONST_DOUBLE bigger, if real values are bigger than |
---|
806 | it normally expects to have room for. |
---|
807 | Note that REAL_VALUE_TYPE is not defined by default, |
---|
808 | since tree.h is not included. But the default dfn as `double' |
---|
809 | would do no harm. */ |
---|
810 | #ifdef REAL_VALUE_TYPE |
---|
811 | i = sizeof (REAL_VALUE_TYPE) / sizeof (rtunion) + 2; |
---|
812 | if (rtx_length[(int) CONST_DOUBLE] < i) |
---|
813 | { |
---|
814 | char *s = (char *) xmalloc (i + 1); |
---|
815 | rtx_length[(int) CONST_DOUBLE] = i; |
---|
816 | rtx_format[(int) CONST_DOUBLE] = s; |
---|
817 | *s++ = 'e'; |
---|
818 | *s++ = '0'; |
---|
819 | /* Set the GET_RTX_FORMAT of CONST_DOUBLE to a string |
---|
820 | of as many `w's as we now have elements. Subtract two from |
---|
821 | the size to account for the 'e' and the '0'. */ |
---|
822 | for (i = 2; i < rtx_length[(int) CONST_DOUBLE]; i++) |
---|
823 | *s++ = 'w'; |
---|
824 | *s++ = 0; |
---|
825 | } |
---|
826 | #endif |
---|
827 | |
---|
828 | #ifdef EXTRA_CC_MODES |
---|
829 | for (i = (int) CCmode + 1; i < (int) MAX_MACHINE_MODE; i++) |
---|
830 | { |
---|
831 | mode_class[i] = MODE_CC; |
---|
832 | mode_size[i] = mode_size[(int) CCmode]; |
---|
833 | mode_unit_size[i] = mode_unit_size[(int) CCmode]; |
---|
834 | mode_wider_mode[i - 1] = (enum machine_mode) i; |
---|
835 | mode_wider_mode[i] = VOIDmode; |
---|
836 | } |
---|
837 | #endif |
---|
838 | |
---|
839 | /* Find the narrowest mode for each class. */ |
---|
840 | |
---|
841 | for (i = 0; i < (int) MAX_MODE_CLASS; i++) |
---|
842 | min_class_size[i] = 1000; |
---|
843 | |
---|
844 | for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; |
---|
845 | mode = (enum machine_mode) ((int) mode + 1)) |
---|
846 | { |
---|
847 | if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)]) |
---|
848 | { |
---|
849 | class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode; |
---|
850 | min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode); |
---|
851 | } |
---|
852 | } |
---|
853 | } |
---|