1 | /* RTL utility routines. |
2 | Copyright (C) 1987-2024 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | /* This file is compiled twice: once for the generator programs |
21 | once for the compiler. */ |
22 | #ifdef GENERATOR_FILE |
23 | #include "bconfig.h" |
24 | #else |
25 | #include "config.h" |
26 | #endif |
27 | |
28 | #include "system.h" |
29 | #include "coretypes.h" |
30 | #include "tm.h" |
31 | #include "rtl.h" |
32 | #ifdef GENERATOR_FILE |
33 | # include "errors.h" |
34 | #else |
35 | # include "rtlhash.h" |
36 | # include "diagnostic-core.h" |
37 | #endif |
38 | |
39 | |
40 | /* Indexed by rtx code, gives number of operands for an rtx with that code. |
41 | Does NOT include rtx header data (code and links). */ |
42 | |
43 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) sizeof FORMAT - 1 , |
44 | |
45 | const unsigned char rtx_length[NUM_RTX_CODE] = { |
46 | #include "rtl.def" |
47 | }; |
48 | |
49 | #undef DEF_RTL_EXPR |
50 | |
51 | /* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */ |
52 | |
53 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME , |
54 | |
55 | const char * const rtx_name[NUM_RTX_CODE] = { |
56 | #include "rtl.def" /* rtl expressions are documented here */ |
57 | }; |
58 | |
59 | #undef DEF_RTL_EXPR |
60 | |
61 | /* Indexed by rtx code, gives a sequence of operand-types for |
62 | rtx's of that code. The sequence is a C string in which |
63 | each character describes one operand. */ |
64 | |
65 | const char * const rtx_format[NUM_RTX_CODE] = { |
66 | /* "*" undefined. |
67 | can cause a warning message |
68 | "0" field is unused (or used in a phase-dependent manner) |
69 | prints nothing |
70 | "i" an integer |
71 | prints the integer |
72 | "n" like "i", but prints entries from `note_insn_name' |
73 | "w" an integer of width HOST_BITS_PER_WIDE_INT |
74 | prints the integer |
75 | "s" a pointer to a string |
76 | prints the string |
77 | "S" like "s", but optional: |
78 | the containing rtx may end before this operand |
79 | "T" like "s", but treated specially by the RTL reader; |
80 | only found in machine description patterns. |
81 | "e" a pointer to an rtl expression |
82 | prints the expression |
83 | "E" a pointer to a vector that points to a number of rtl expressions |
84 | prints a list of the rtl expressions |
85 | "V" like "E", but optional: |
86 | the containing rtx may end before this operand |
87 | "u" a pointer to another insn |
88 | prints the uid of the insn. |
89 | "b" is a pointer to a bitmap header. |
90 | "B" is a basic block pointer. |
91 | "t" is a tree pointer. |
92 | "r" a register. |
93 | "p" is a poly_uint16 offset. */ |
94 | |
95 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT , |
96 | #include "rtl.def" /* rtl expressions are defined here */ |
97 | #undef DEF_RTL_EXPR |
98 | }; |
99 | |
100 | /* Indexed by rtx code, gives a character representing the "class" of |
101 | that rtx code. See rtl.def for documentation on the defined classes. */ |
102 | |
103 | const enum rtx_class rtx_class[NUM_RTX_CODE] = { |
104 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS, |
105 | #include "rtl.def" /* rtl expressions are defined here */ |
106 | #undef DEF_RTL_EXPR |
107 | }; |
108 | |
109 | /* Whether rtxs with the given code store data in the hwint field. */ |
110 | |
111 | #define RTX_CODE_HWINT_P_1(ENUM) \ |
112 | ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \ |
113 | || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT) |
114 | #ifdef GENERATOR_FILE |
115 | #define RTX_CODE_HWINT_P(ENUM) \ |
116 | (RTX_CODE_HWINT_P_1 (ENUM) || (ENUM) == EQ_ATTR_ALT) |
117 | #else |
118 | #define RTX_CODE_HWINT_P RTX_CODE_HWINT_P_1 |
119 | #endif |
120 | |
121 | /* Indexed by rtx code, gives the size of the rtx in bytes. */ |
122 | |
123 | const unsigned char rtx_code_size[NUM_RTX_CODE] = { |
124 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \ |
125 | (RTX_CODE_HWINT_P (ENUM) \ |
126 | ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT) \ |
127 | : (ENUM) == REG \ |
128 | ? RTX_HDR_SIZE + sizeof (reg_info) \ |
129 | : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)), |
130 | |
131 | #include "rtl.def" |
132 | #undef DEF_RTL_EXPR |
133 | }; |
134 | |
135 | /* Names for kinds of NOTEs and REG_NOTEs. */ |
136 | |
137 | const char * const note_insn_name[NOTE_INSN_MAX] = |
138 | { |
139 | #define DEF_INSN_NOTE(NAME) #NAME, |
140 | #include "insn-notes.def" |
141 | #undef DEF_INSN_NOTE |
142 | }; |
143 | |
144 | const char * const reg_note_name[REG_NOTE_MAX] = |
145 | { |
146 | #define DEF_REG_NOTE(NAME) #NAME, |
147 | #include "reg-notes.def" |
148 | #undef DEF_REG_NOTE |
149 | }; |
150 | |
151 | static size_t rtx_alloc_counts[(int) LAST_AND_UNUSED_RTX_CODE]; |
152 | static size_t rtx_alloc_sizes[(int) LAST_AND_UNUSED_RTX_CODE]; |
153 | static size_t rtvec_alloc_counts; |
154 | static size_t rtvec_alloc_sizes; |
155 | |
156 | |
157 | /* Allocate an rtx vector of N elements. |
158 | Store the length, and initialize all elements to zero. */ |
159 | |
160 | rtvec |
161 | rtvec_alloc (size_t n) |
162 | { |
163 | rtvec rt; |
164 | |
165 | /* rtvec_def.num_elem is an int. */ |
166 | gcc_assert (n < INT_MAX); |
167 | |
168 | rt = ggc_alloc_rtvec_sized (n); |
169 | /* Clear out the vector. */ |
170 | memset (s: &rt->elem[0], c: 0, n: n * sizeof (rtx)); |
171 | |
172 | PUT_NUM_ELEM (rt, n); |
173 | |
174 | if (GATHER_STATISTICS) |
175 | { |
176 | rtvec_alloc_counts++; |
177 | rtvec_alloc_sizes += n * sizeof (rtx); |
178 | } |
179 | |
180 | return rt; |
181 | } |
182 | |
183 | /* Create a bitwise copy of VEC. */ |
184 | |
185 | rtvec |
186 | shallow_copy_rtvec (rtvec vec) |
187 | { |
188 | rtvec newvec; |
189 | int n; |
190 | |
191 | n = GET_NUM_ELEM (vec); |
192 | newvec = rtvec_alloc (n); |
193 | memcpy (dest: &newvec->elem[0], src: &vec->elem[0], n: sizeof (rtx) * n); |
194 | return newvec; |
195 | } |
196 | |
197 | /* Return the number of bytes occupied by rtx value X. */ |
198 | |
199 | unsigned int |
200 | rtx_size (const_rtx x) |
201 | { |
202 | if (CONST_WIDE_INT_P (x)) |
203 | return (RTX_HDR_SIZE |
204 | + sizeof (struct hwivec_def) |
205 | + ((CONST_WIDE_INT_NUNITS (x) - 1) |
206 | * sizeof (HOST_WIDE_INT))); |
207 | if (CONST_POLY_INT_P (x)) |
208 | return (RTX_HDR_SIZE |
209 | + sizeof (struct const_poly_int_def) |
210 | + CONST_POLY_INT_COEFFS (x).extra_size ()); |
211 | if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x)) |
212 | return RTX_HDR_SIZE + sizeof (struct block_symbol); |
213 | return RTX_CODE_SIZE (GET_CODE (x)); |
214 | } |
215 | |
216 | /* Allocate an rtx of code CODE with EXTRA bytes in it. The CODE is |
217 | stored in the rtx; all the rest is initialized to zero. */ |
218 | |
219 | rtx |
220 | rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int ) |
221 | { |
222 | rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) + extra |
223 | PASS_MEM_STAT); |
224 | |
225 | rtx_init (rt, code); |
226 | |
227 | if (GATHER_STATISTICS) |
228 | { |
229 | rtx_alloc_counts[code]++; |
230 | rtx_alloc_sizes[code] += RTX_CODE_SIZE (code); |
231 | } |
232 | |
233 | return rt; |
234 | } |
235 | |
236 | /* Allocate an rtx of code CODE. The CODE is stored in the rtx; |
237 | all the rest is initialized to zero. */ |
238 | |
239 | rtx |
240 | rtx_alloc (RTX_CODE code MEM_STAT_DECL) |
241 | { |
242 | return rtx_alloc_stat_v (code PASS_MEM_STAT, extra: 0); |
243 | } |
244 | |
245 | /* Write the wide constant X to OUTFILE. */ |
246 | |
247 | void |
248 | cwi_output_hex (FILE *outfile, const_rtx x) |
249 | { |
250 | int i = CWI_GET_NUM_ELEM (x); |
251 | gcc_assert (i > 0); |
252 | if (CWI_ELT (x, i - 1) == 0) |
253 | /* The HOST_WIDE_INT_PRINT_HEX prepends a 0x only if the val is |
254 | non zero. We want all numbers to have a 0x prefix. */ |
255 | fprintf (stream: outfile, format: "0x" ); |
256 | fprintf (stream: outfile, HOST_WIDE_INT_PRINT_HEX, CWI_ELT (x, --i)); |
257 | while (--i >= 0) |
258 | fprintf (stream: outfile, HOST_WIDE_INT_PRINT_PADDED_HEX, CWI_ELT (x, i)); |
259 | } |
260 | |
261 | |
262 | /* Return true if ORIG is a sharable CONST. */ |
263 | |
264 | bool |
265 | shared_const_p (const_rtx orig) |
266 | { |
267 | gcc_assert (GET_CODE (orig) == CONST); |
268 | |
269 | /* CONST can be shared if it contains a SYMBOL_REF. If it contains |
270 | a LABEL_REF, it isn't sharable. */ |
271 | poly_int64 offset; |
272 | return (GET_CODE (XEXP (orig, 0)) == PLUS |
273 | && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF |
274 | && poly_int_rtx_p (XEXP (XEXP (orig, 0), 1), res: &offset)); |
275 | } |
276 | |
277 | |
278 | /* Create a new copy of an rtx. |
279 | Recursively copies the operands of the rtx, |
280 | except for those few rtx codes that are sharable. */ |
281 | |
282 | rtx |
283 | copy_rtx (rtx orig) |
284 | { |
285 | rtx copy; |
286 | int i, j; |
287 | RTX_CODE code; |
288 | const char *format_ptr; |
289 | |
290 | code = GET_CODE (orig); |
291 | |
292 | switch (code) |
293 | { |
294 | case REG: |
295 | case DEBUG_EXPR: |
296 | case VALUE: |
297 | CASE_CONST_ANY: |
298 | case SYMBOL_REF: |
299 | case CODE_LABEL: |
300 | case PC: |
301 | case RETURN: |
302 | case SIMPLE_RETURN: |
303 | case SCRATCH: |
304 | /* SCRATCH must be shared because they represent distinct values. */ |
305 | return orig; |
306 | case CLOBBER: |
307 | /* Share clobbers of hard registers, but do not share pseudo reg |
308 | clobbers or clobbers of hard registers that originated as pseudos. |
309 | This is needed to allow safe register renaming. */ |
310 | if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER |
311 | && ORIGINAL_REGNO (XEXP (orig, 0)) == REGNO (XEXP (orig, 0))) |
312 | return orig; |
313 | break; |
314 | |
315 | case CONST: |
316 | if (shared_const_p (orig)) |
317 | return orig; |
318 | break; |
319 | |
320 | /* A MEM with a constant address is not sharable. The problem is that |
321 | the constant address may need to be reloaded. If the mem is shared, |
322 | then reloading one copy of this mem will cause all copies to appear |
323 | to have been reloaded. */ |
324 | |
325 | default: |
326 | break; |
327 | } |
328 | |
329 | /* Copy the various flags, fields, and other information. We assume |
330 | that all fields need copying, and then clear the fields that should |
331 | not be copied. That is the sensible default behavior, and forces |
332 | us to explicitly document why we are *not* copying a flag. */ |
333 | copy = shallow_copy_rtx (orig); |
334 | |
335 | format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); |
336 | |
337 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) |
338 | switch (*format_ptr++) |
339 | { |
340 | case 'e': |
341 | if (XEXP (orig, i) != NULL) |
342 | XEXP (copy, i) = copy_rtx (XEXP (orig, i)); |
343 | break; |
344 | |
345 | case 'E': |
346 | case 'V': |
347 | if (XVEC (orig, i) != NULL) |
348 | { |
349 | XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); |
350 | for (j = 0; j < XVECLEN (copy, i); j++) |
351 | XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j)); |
352 | } |
353 | break; |
354 | |
355 | case 't': |
356 | case 'w': |
357 | case 'i': |
358 | case 'p': |
359 | case 's': |
360 | case 'S': |
361 | case 'T': |
362 | case 'u': |
363 | case 'B': |
364 | case '0': |
365 | /* These are left unchanged. */ |
366 | break; |
367 | |
368 | default: |
369 | gcc_unreachable (); |
370 | } |
371 | return copy; |
372 | } |
373 | |
374 | /* Create a new copy of an rtx. Only copy just one level. */ |
375 | |
376 | rtx |
377 | shallow_copy_rtx (const_rtx orig MEM_STAT_DECL) |
378 | { |
379 | const unsigned int size = rtx_size (x: orig); |
380 | rtx const copy = ggc_alloc_rtx_def_stat (s: size PASS_MEM_STAT); |
381 | memcpy (dest: copy, src: orig, n: size); |
382 | switch (GET_CODE (orig)) |
383 | { |
384 | /* RTX codes copy_rtx_if_shared_1 considers are shareable, |
385 | the used flag is often used for other purposes. */ |
386 | case REG: |
387 | case DEBUG_EXPR: |
388 | case VALUE: |
389 | CASE_CONST_ANY: |
390 | case SYMBOL_REF: |
391 | case CODE_LABEL: |
392 | case PC: |
393 | case RETURN: |
394 | case SIMPLE_RETURN: |
395 | case SCRATCH: |
396 | break; |
397 | default: |
398 | /* For all other RTXes clear the used flag on the copy. |
399 | CALL_INSN use "used" flag to indicate it's a fake call. */ |
400 | if (!INSN_P (orig)) |
401 | RTX_FLAG (copy, used) = 0; |
402 | break; |
403 | } |
404 | return copy; |
405 | } |
406 | |
407 | /* Nonzero when we are generating CONCATs. */ |
408 | int generating_concat_p; |
409 | |
410 | /* Nonzero when we are expanding trees to RTL. */ |
411 | int currently_expanding_to_rtl; |
412 | |
413 | |
414 | |
415 | /* Return true if X and Y are identical-looking rtx's. |
416 | This is the Lisp function EQUAL for rtx arguments. |
417 | |
418 | Call CB on each pair of rtx if CB is not NULL. |
419 | When the callback returns true, we continue with the new pair. */ |
420 | |
421 | bool |
422 | rtx_equal_p (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb) |
423 | { |
424 | int i; |
425 | int j; |
426 | enum rtx_code code; |
427 | const char *fmt; |
428 | rtx nx, ny; |
429 | |
430 | if (x == y) |
431 | return true; |
432 | if (x == 0 || y == 0) |
433 | return false; |
434 | |
435 | /* Invoke the callback first. */ |
436 | if (cb != NULL |
437 | && ((*cb) (&x, &y, &nx, &ny))) |
438 | return rtx_equal_p (x: nx, y: ny, cb); |
439 | |
440 | code = GET_CODE (x); |
441 | /* Rtx's of different codes cannot be equal. */ |
442 | if (code != GET_CODE (y)) |
443 | return false; |
444 | |
445 | /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. |
446 | (REG:SI x) and (REG:HI x) are NOT equivalent. */ |
447 | |
448 | if (GET_MODE (x) != GET_MODE (y)) |
449 | return false; |
450 | |
451 | /* MEMs referring to different address space are not equivalent. */ |
452 | if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) |
453 | return false; |
454 | |
455 | /* Some RTL can be compared nonrecursively. */ |
456 | switch (code) |
457 | { |
458 | case REG: |
459 | return (REGNO (x) == REGNO (y)); |
460 | |
461 | case LABEL_REF: |
462 | return label_ref_label (ref: x) == label_ref_label (ref: y); |
463 | |
464 | case SYMBOL_REF: |
465 | return XSTR (x, 0) == XSTR (y, 0); |
466 | |
467 | case DEBUG_EXPR: |
468 | case VALUE: |
469 | case SCRATCH: |
470 | CASE_CONST_UNIQUE: |
471 | return false; |
472 | |
473 | case CONST_VECTOR: |
474 | if (!same_vector_encodings_p (x, y)) |
475 | return false; |
476 | break; |
477 | |
478 | case DEBUG_IMPLICIT_PTR: |
479 | return DEBUG_IMPLICIT_PTR_DECL (x) |
480 | == DEBUG_IMPLICIT_PTR_DECL (y); |
481 | |
482 | case DEBUG_PARAMETER_REF: |
483 | return DEBUG_PARAMETER_REF_DECL (x) |
484 | == DEBUG_PARAMETER_REF_DECL (y); |
485 | |
486 | case ENTRY_VALUE: |
487 | return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y), cb); |
488 | |
489 | default: |
490 | break; |
491 | } |
492 | |
493 | /* Compare the elements. If any pair of corresponding elements |
494 | fail to match, return 0 for the whole thing. */ |
495 | |
496 | fmt = GET_RTX_FORMAT (code); |
497 | for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
498 | { |
499 | switch (fmt[i]) |
500 | { |
501 | case 'w': |
502 | if (XWINT (x, i) != XWINT (y, i)) |
503 | return false; |
504 | break; |
505 | |
506 | case 'n': |
507 | case 'i': |
508 | if (XINT (x, i) != XINT (y, i)) |
509 | { |
510 | #ifndef GENERATOR_FILE |
511 | if (((code == ASM_OPERANDS && i == 6) |
512 | || (code == ASM_INPUT && i == 1)) |
513 | && XINT (x, i) == XINT (y, i)) |
514 | break; |
515 | #endif |
516 | return false; |
517 | } |
518 | break; |
519 | |
520 | case 'p': |
521 | if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y))) |
522 | return false; |
523 | break; |
524 | |
525 | case 'V': |
526 | case 'E': |
527 | /* Two vectors must have the same length. */ |
528 | if (XVECLEN (x, i) != XVECLEN (y, i)) |
529 | return false; |
530 | |
531 | /* And the corresponding elements must match. */ |
532 | for (j = 0; j < XVECLEN (x, i); j++) |
533 | if (!rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j), cb)) |
534 | return false; |
535 | break; |
536 | |
537 | case 'e': |
538 | if (!rtx_equal_p (XEXP (x, i), XEXP (y, i), cb)) |
539 | return false; |
540 | break; |
541 | |
542 | case 'S': |
543 | case 's': |
544 | if ((XSTR (x, i) || XSTR (y, i)) |
545 | && (! XSTR (x, i) || ! XSTR (y, i) |
546 | || strcmp (XSTR (x, i), XSTR (y, i)))) |
547 | return false; |
548 | break; |
549 | |
550 | case 'u': |
551 | /* These are just backpointers, so they don't matter. */ |
552 | break; |
553 | |
554 | case '0': |
555 | case 't': |
556 | break; |
557 | |
558 | /* It is believed that rtx's at this level will never |
559 | contain anything but integers and other rtx's, |
560 | except for within LABEL_REFs and SYMBOL_REFs. */ |
561 | default: |
562 | gcc_unreachable (); |
563 | } |
564 | } |
565 | return true; |
566 | } |
567 | |
568 | /* Return true if all elements of VEC are equal. */ |
569 | |
570 | bool |
571 | rtvec_all_equal_p (const_rtvec vec) |
572 | { |
573 | const_rtx first = RTVEC_ELT (vec, 0); |
574 | /* Optimize the important special case of a vector of constants. |
575 | The main use of this function is to detect whether every element |
576 | of CONST_VECTOR is the same. */ |
577 | switch (GET_CODE (first)) |
578 | { |
579 | CASE_CONST_UNIQUE: |
580 | for (int i = 1, n = GET_NUM_ELEM (vec); i < n; ++i) |
581 | if (first != RTVEC_ELT (vec, i)) |
582 | return false; |
583 | return true; |
584 | |
585 | default: |
586 | for (int i = 1, n = GET_NUM_ELEM (vec); i < n; ++i) |
587 | if (!rtx_equal_p (x: first, RTVEC_ELT (vec, i))) |
588 | return false; |
589 | return true; |
590 | } |
591 | } |
592 | |
593 | /* Return true if VEC contains a linear series of integers |
594 | { START, START+1, START+2, ... }. */ |
595 | |
596 | bool |
597 | rtvec_series_p (rtvec vec, int start) |
598 | { |
599 | for (int i = 0; i < GET_NUM_ELEM (vec); i++) |
600 | { |
601 | rtx x = RTVEC_ELT (vec, i); |
602 | if (!CONST_INT_P (x) || INTVAL (x) != i + start) |
603 | return false; |
604 | } |
605 | return true; |
606 | } |
607 | |
608 | /* Return an indication of which type of insn should have X as a body. |
609 | In generator files, this can be UNKNOWN if the answer is only known |
610 | at (GCC) runtime. Otherwise the value is CODE_LABEL, INSN, CALL_INSN |
611 | or JUMP_INSN. */ |
612 | |
613 | enum rtx_code |
614 | classify_insn (rtx x) |
615 | { |
616 | if (LABEL_P (x)) |
617 | return CODE_LABEL; |
618 | if (GET_CODE (x) == CALL) |
619 | return CALL_INSN; |
620 | if (ANY_RETURN_P (x)) |
621 | return JUMP_INSN; |
622 | if (GET_CODE (x) == ASM_OPERANDS && ASM_OPERANDS_LABEL_LENGTH (x)) |
623 | return JUMP_INSN; |
624 | if (GET_CODE (x) == SET) |
625 | { |
626 | if (GET_CODE (SET_DEST (x)) == PC) |
627 | return JUMP_INSN; |
628 | else if (GET_CODE (SET_SRC (x)) == CALL) |
629 | return CALL_INSN; |
630 | else |
631 | return INSN; |
632 | } |
633 | if (GET_CODE (x) == PARALLEL) |
634 | { |
635 | int j; |
636 | bool has_return_p = false; |
637 | for (j = XVECLEN (x, 0) - 1; j >= 0; j--) |
638 | if (GET_CODE (XVECEXP (x, 0, j)) == CALL) |
639 | return CALL_INSN; |
640 | else if (ANY_RETURN_P (XVECEXP (x, 0, j))) |
641 | has_return_p = true; |
642 | else if (GET_CODE (XVECEXP (x, 0, j)) == SET |
643 | && GET_CODE (SET_DEST (XVECEXP (x, 0, j))) == PC) |
644 | return JUMP_INSN; |
645 | else if (GET_CODE (XVECEXP (x, 0, j)) == SET |
646 | && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL) |
647 | return CALL_INSN; |
648 | if (has_return_p) |
649 | return JUMP_INSN; |
650 | if (GET_CODE (XVECEXP (x, 0, 0)) == ASM_OPERANDS |
651 | && ASM_OPERANDS_LABEL_LENGTH (XVECEXP (x, 0, 0))) |
652 | return JUMP_INSN; |
653 | } |
654 | #ifdef GENERATOR_FILE |
655 | if (GET_CODE (x) == MATCH_OPERAND |
656 | || GET_CODE (x) == MATCH_OPERATOR |
657 | || GET_CODE (x) == MATCH_PARALLEL |
658 | || GET_CODE (x) == MATCH_OP_DUP |
659 | || GET_CODE (x) == MATCH_DUP |
660 | || GET_CODE (x) == PARALLEL) |
661 | return UNKNOWN; |
662 | #endif |
663 | return INSN; |
664 | } |
665 | |
666 | /* Comparator of indices based on rtx_alloc_counts. */ |
667 | |
668 | static int |
669 | rtx_count_cmp (const void *p1, const void *p2) |
670 | { |
671 | const unsigned *n1 = (const unsigned *)p1; |
672 | const unsigned *n2 = (const unsigned *)p2; |
673 | |
674 | return rtx_alloc_counts[*n1] - rtx_alloc_counts[*n2]; |
675 | } |
676 | |
677 | void |
678 | dump_rtx_statistics (void) |
679 | { |
680 | int total_counts = 0; |
681 | int total_sizes = 0; |
682 | |
683 | if (! GATHER_STATISTICS) |
684 | { |
685 | fprintf (stderr, format: "No RTX statistics\n" ); |
686 | return; |
687 | } |
688 | |
689 | fprintf (stderr, format: "\nRTX Kind Count Bytes\n" ); |
690 | fprintf (stderr, format: "-------------------------------------------\n" ); |
691 | |
692 | auto_vec<unsigned> indices (LAST_AND_UNUSED_RTX_CODE); |
693 | for (unsigned i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++) |
694 | indices.quick_push (obj: i); |
695 | indices.qsort (rtx_count_cmp); |
696 | |
697 | for (unsigned i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++) |
698 | { |
699 | unsigned j = indices[i]; |
700 | if (rtx_alloc_counts[j]) |
701 | { |
702 | fprintf (stderr, format: "%-24s " PRsa (6) " " PRsa (9) "\n" , |
703 | GET_RTX_NAME (j), |
704 | SIZE_AMOUNT (rtx_alloc_counts[j]), |
705 | SIZE_AMOUNT (rtx_alloc_sizes[j])); |
706 | total_counts += rtx_alloc_counts[j]; |
707 | total_sizes += rtx_alloc_sizes[j]; |
708 | } |
709 | } |
710 | |
711 | if (rtvec_alloc_counts) |
712 | { |
713 | fprintf (stderr, format: "%-24s " PRsa (6) " " PRsa (9) "\n" , "rtvec" , |
714 | SIZE_AMOUNT (rtvec_alloc_counts), |
715 | SIZE_AMOUNT (rtvec_alloc_sizes)); |
716 | total_counts += rtvec_alloc_counts; |
717 | total_sizes += rtvec_alloc_sizes; |
718 | } |
719 | fprintf (stderr, format: "-----------------------------------------------\n" ); |
720 | fprintf (stderr, format: "%-24s " PRsa (6) " " PRsa (9) "\n" , |
721 | "Total" , SIZE_AMOUNT (total_counts), |
722 | SIZE_AMOUNT (total_sizes)); |
723 | fprintf (stderr, format: "-----------------------------------------------\n" ); |
724 | } |
725 | |
726 | #if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007) |
727 | |
728 | /* Disable warnings about missing quoting in GCC diagnostics for |
729 | the internal_error calls. Their format strings deliberately don't |
730 | follow GCC diagnostic conventions. */ |
731 | #if __GNUC__ >= 10 |
732 | #pragma GCC diagnostic push |
733 | #pragma GCC diagnostic ignored "-Wformat-diag" |
734 | #endif |
735 | |
736 | void |
737 | rtl_check_failed_bounds (const_rtx r, int n, const char *file, int line, |
738 | const char *func) |
739 | { |
740 | internal_error |
741 | ("RTL check: access of elt %d of '%s' with last elt %d in %s, at %s:%d" , |
742 | n, GET_RTX_NAME (GET_CODE (r)), GET_RTX_LENGTH (GET_CODE (r)) - 1, |
743 | func, trim_filename (file), line); |
744 | } |
745 | |
746 | void |
747 | rtl_check_failed_type1 (const_rtx r, int n, int c1, const char *file, int line, |
748 | const char *func) |
749 | { |
750 | internal_error |
751 | ("RTL check: expected elt %d type '%c', have '%c' (rtx %s) in %s, at %s:%d" , |
752 | n, c1, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)), |
753 | func, trim_filename (file), line); |
754 | } |
755 | |
756 | void |
757 | rtl_check_failed_type2 (const_rtx r, int n, int c1, int c2, const char *file, |
758 | int line, const char *func) |
759 | { |
760 | internal_error |
761 | ("RTL check: expected elt %d type '%c' or '%c', have '%c' (rtx %s) in %s, at %s:%d" , |
762 | n, c1, c2, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)), |
763 | func, trim_filename (file), line); |
764 | } |
765 | |
766 | void |
767 | rtl_check_failed_code1 (const_rtx r, enum rtx_code code, const char *file, |
768 | int line, const char *func) |
769 | { |
770 | internal_error ("RTL check: expected code '%s', have '%s' in %s, at %s:%d" , |
771 | GET_RTX_NAME (code), GET_RTX_NAME (GET_CODE (r)), func, |
772 | trim_filename (file), line); |
773 | } |
774 | |
775 | void |
776 | rtl_check_failed_code2 (const_rtx r, enum rtx_code code1, enum rtx_code code2, |
777 | const char *file, int line, const char *func) |
778 | { |
779 | internal_error |
780 | ("RTL check: expected code '%s' or '%s', have '%s' in %s, at %s:%d" , |
781 | GET_RTX_NAME (code1), GET_RTX_NAME (code2), GET_RTX_NAME (GET_CODE (r)), |
782 | func, trim_filename (file), line); |
783 | } |
784 | |
785 | void |
786 | rtl_check_failed_code3 (const_rtx r, enum rtx_code code1, enum rtx_code code2, |
787 | enum rtx_code code3, const char *file, int line, |
788 | const char *func) |
789 | { |
790 | internal_error |
791 | ("RTL check: expected code '%s', '%s' or '%s', have '%s' in %s, at %s:%d" , |
792 | GET_RTX_NAME (code1), GET_RTX_NAME (code2), GET_RTX_NAME (code3), |
793 | GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line); |
794 | } |
795 | |
796 | void |
797 | rtl_check_failed_code_mode (const_rtx r, enum rtx_code code, machine_mode mode, |
798 | bool not_mode, const char *file, int line, |
799 | const char *func) |
800 | { |
801 | internal_error ((not_mode |
802 | ? ("RTL check: expected code '%s' and not mode '%s', " |
803 | "have code '%s' and mode '%s' in %s, at %s:%d" ) |
804 | : ("RTL check: expected code '%s' and mode '%s', " |
805 | "have code '%s' and mode '%s' in %s, at %s:%d" )), |
806 | GET_RTX_NAME (code), GET_MODE_NAME (mode), |
807 | GET_RTX_NAME (GET_CODE (r)), GET_MODE_NAME (GET_MODE (r)), |
808 | func, trim_filename (file), line); |
809 | } |
810 | |
811 | #if __GNUC__ >= 10 |
812 | #pragma GCC diagnostic pop |
813 | #endif |
814 | |
815 | /* Report that line LINE of FILE tried to access the block symbol fields |
816 | of a non-block symbol. FUNC is the function that contains the line. */ |
817 | |
818 | void |
819 | rtl_check_failed_block_symbol (const char *file, int line, const char *func) |
820 | { |
821 | internal_error |
822 | ("RTL check: attempt to treat non-block symbol as a block symbol " |
823 | "in %s, at %s:%d" , func, trim_filename (file), line); |
824 | } |
825 | |
826 | /* XXX Maybe print the vector? */ |
827 | void |
828 | cwi_check_failed_bounds (const_rtx x, int n, const char *file, int line, |
829 | const char *func) |
830 | { |
831 | internal_error |
832 | ("RTL check: access of hwi elt %d of vector with last elt %d in %s, at %s:%d" , |
833 | n, CWI_GET_NUM_ELEM (x) - 1, func, trim_filename (file), line); |
834 | } |
835 | |
836 | /* XXX Maybe print the vector? */ |
837 | void |
838 | rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line, |
839 | const char *func) |
840 | { |
841 | internal_error |
842 | ("RTL check: access of elt %d of vector with last elt %d in %s, at %s:%d" , |
843 | n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line); |
844 | } |
845 | #endif /* ENABLE_RTL_CHECKING */ |
846 | |
847 | #if defined ENABLE_RTL_FLAG_CHECKING |
848 | void |
849 | rtl_check_failed_flag (const char *name, const_rtx r, const char *file, |
850 | int line, const char *func) |
851 | { |
852 | internal_error |
853 | ("RTL flag check: %s used with unexpected rtx code '%s' in %s, at %s:%d" , |
854 | name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line); |
855 | } |
856 | #endif /* ENABLE_RTL_FLAG_CHECKING */ |
857 | |