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 */ |
---|