]>
Commit | Line | Data |
---|---|---|
c62c2659 BS |
1 | /* Instruction scheduling pass. |
2 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, | |
cf403648 | 3 | 1999, 2000, 2002 Free Software Foundation, Inc. |
c62c2659 BS |
4 | Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by, |
5 | and currently maintained by, Jim Wilson (wilson@cygnus.com) | |
6 | ||
1322177d | 7 | This file is part of GCC. |
c62c2659 | 8 | |
1322177d LB |
9 | GCC is free software; you can redistribute it and/or modify it under |
10 | the terms of the GNU General Public License as published by the Free | |
11 | Software Foundation; either version 2, or (at your option) any later | |
12 | version. | |
c62c2659 | 13 | |
1322177d LB |
14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
c62c2659 BS |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
17 | for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
47a1bd82 NC |
20 | along with GCC; see the file COPYING. If not, write to the Free |
21 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
c62c2659 BS |
22 | 02111-1307, USA. */ |
23 | \f | |
24 | #include "config.h" | |
25 | #include "system.h" | |
26 | #include "toplev.h" | |
27 | #include "rtl.h" | |
28 | #include "tm_p.h" | |
29 | #include "regs.h" | |
18e720b3 BS |
30 | #include "hard-reg-set.h" |
31 | #include "basic-block.h" | |
c62c2659 | 32 | #include "insn-attr.h" |
b3ae1ccd | 33 | #include "real.h" |
c62c2659 | 34 | #include "sched-int.h" |
fae15c93 | 35 | #include "target.h" |
c62c2659 | 36 | |
f56887a7 | 37 | #ifdef INSN_SCHEDULING |
c62c2659 BS |
38 | /* target_units bitmask has 1 for each unit in the cpu. It should be |
39 | possible to compute this variable from the machine description. | |
40 | But currently it is computed by examining the insn list. Since | |
41 | this is only needed for visualization, it seems an acceptable | |
42 | solution. (For understanding the mapping of bits to units, see | |
fae15c93 VM |
43 | definition of function_units[] in "insn-attrtab.c".) The scheduler |
44 | using only DFA description should never use the following variable. */ | |
c62c2659 BS |
45 | |
46 | static int target_units = 0; | |
47 | ||
48 | static char *safe_concat PARAMS ((char *, char *, const char *)); | |
49 | static int get_visual_tbl_length PARAMS ((void)); | |
50 | static void print_exp PARAMS ((char *, rtx, int)); | |
51 | static void print_value PARAMS ((char *, rtx, int)); | |
52 | static void print_pattern PARAMS ((char *, rtx, int)); | |
c62c2659 BS |
53 | |
54 | /* Print names of units on which insn can/should execute, for debugging. */ | |
55 | ||
56 | void | |
57 | insn_print_units (insn) | |
58 | rtx insn; | |
59 | { | |
60 | int i; | |
61 | int unit = insn_unit (insn); | |
62 | ||
63 | if (unit == -1) | |
64 | fprintf (sched_dump, "none"); | |
65 | else if (unit >= 0) | |
66 | fprintf (sched_dump, "%s", function_units[unit].name); | |
67 | else | |
68 | { | |
69 | fprintf (sched_dump, "["); | |
70 | for (i = 0, unit = ~unit; unit; i++, unit >>= 1) | |
71 | if (unit & 1) | |
72 | { | |
73 | fprintf (sched_dump, "%s", function_units[i].name); | |
74 | if (unit != 1) | |
75 | fprintf (sched_dump, " "); | |
76 | } | |
77 | fprintf (sched_dump, "]"); | |
78 | } | |
79 | } | |
80 | ||
81 | /* MAX_VISUAL_LINES is the maximum number of lines in visualization table | |
82 | of a basic block. If more lines are needed, table is splitted to two. | |
83 | n_visual_lines is the number of lines printed so far for a block. | |
84 | visual_tbl contains the block visualization info. | |
85 | vis_no_unit holds insns in a cycle that are not mapped to any unit. */ | |
86 | #define MAX_VISUAL_LINES 100 | |
87 | #define INSN_LEN 30 | |
88 | int n_visual_lines; | |
4c42e347 | 89 | static unsigned visual_tbl_line_length; |
c62c2659 BS |
90 | char *visual_tbl; |
91 | int n_vis_no_unit; | |
b1b6b0cb GS |
92 | #define MAX_VISUAL_NO_UNIT 20 |
93 | rtx vis_no_unit[MAX_VISUAL_NO_UNIT]; | |
c62c2659 | 94 | |
f63d1bf7 | 95 | /* Finds units that are in use in this function. Required only |
c62c2659 BS |
96 | for visualization. */ |
97 | ||
98 | void | |
99 | init_target_units () | |
100 | { | |
101 | rtx insn; | |
102 | int unit; | |
103 | ||
104 | for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) | |
105 | { | |
106 | if (! INSN_P (insn)) | |
107 | continue; | |
108 | ||
109 | unit = insn_unit (insn); | |
110 | ||
111 | if (unit < 0) | |
112 | target_units |= ~unit; | |
113 | else | |
114 | target_units |= (1 << unit); | |
115 | } | |
116 | } | |
117 | ||
118 | /* Return the length of the visualization table. */ | |
119 | ||
120 | static int | |
121 | get_visual_tbl_length () | |
122 | { | |
123 | int unit, i; | |
124 | int n, n1; | |
125 | char *s; | |
126 | ||
fae15c93 VM |
127 | if (targetm.sched.use_dfa_pipeline_interface |
128 | && (*targetm.sched.use_dfa_pipeline_interface) ()) | |
129 | { | |
130 | visual_tbl_line_length = 1; | |
131 | return 1; /* Can't return 0 because that will cause problems | |
132 | with alloca. */ | |
133 | } | |
134 | ||
c62c2659 BS |
135 | /* Compute length of one field in line. */ |
136 | s = (char *) alloca (INSN_LEN + 6); | |
137 | sprintf (s, " %33s", "uname"); | |
138 | n1 = strlen (s); | |
139 | ||
140 | /* Compute length of one line. */ | |
141 | n = strlen (";; "); | |
142 | n += n1; | |
143 | for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++) | |
144 | if (function_units[unit].bitmask & target_units) | |
145 | for (i = 0; i < function_units[unit].multiplicity; i++) | |
146 | n += n1; | |
147 | n += n1; | |
148 | n += strlen ("\n") + 2; | |
149 | ||
4c42e347 AO |
150 | visual_tbl_line_length = n; |
151 | ||
c62c2659 BS |
152 | /* Compute length of visualization string. */ |
153 | return (MAX_VISUAL_LINES * n); | |
154 | } | |
155 | ||
156 | /* Init block visualization debugging info. */ | |
157 | ||
158 | void | |
159 | init_block_visualization () | |
160 | { | |
161 | strcpy (visual_tbl, ""); | |
162 | n_visual_lines = 0; | |
163 | n_vis_no_unit = 0; | |
164 | } | |
165 | ||
166 | #define BUF_LEN 2048 | |
167 | ||
168 | static char * | |
169 | safe_concat (buf, cur, str) | |
170 | char *buf; | |
171 | char *cur; | |
172 | const char *str; | |
173 | { | |
174 | char *end = buf + BUF_LEN - 2; /* Leave room for null. */ | |
175 | int c; | |
176 | ||
177 | if (cur > end) | |
178 | { | |
179 | *end = '\0'; | |
180 | return end; | |
181 | } | |
182 | ||
183 | while (cur < end && (c = *str++) != '\0') | |
184 | *cur++ = c; | |
185 | ||
186 | *cur = '\0'; | |
187 | return cur; | |
188 | } | |
189 | ||
190 | /* This recognizes rtx, I classified as expressions. These are always | |
191 | represent some action on values or results of other expression, that | |
192 | may be stored in objects representing values. */ | |
193 | ||
194 | static void | |
195 | print_exp (buf, x, verbose) | |
196 | char *buf; | |
197 | rtx x; | |
198 | int verbose; | |
199 | { | |
200 | char tmp[BUF_LEN]; | |
201 | const char *st[4]; | |
202 | char *cur = buf; | |
203 | const char *fun = (char *) 0; | |
204 | const char *sep; | |
205 | rtx op[4]; | |
206 | int i; | |
207 | ||
208 | for (i = 0; i < 4; i++) | |
209 | { | |
210 | st[i] = (char *) 0; | |
211 | op[i] = NULL_RTX; | |
212 | } | |
213 | ||
214 | switch (GET_CODE (x)) | |
215 | { | |
216 | case PLUS: | |
217 | op[0] = XEXP (x, 0); | |
218 | if (GET_CODE (XEXP (x, 1)) == CONST_INT | |
219 | && INTVAL (XEXP (x, 1)) < 0) | |
220 | { | |
221 | st[1] = "-"; | |
222 | op[1] = GEN_INT (-INTVAL (XEXP (x, 1))); | |
223 | } | |
224 | else | |
225 | { | |
226 | st[1] = "+"; | |
227 | op[1] = XEXP (x, 1); | |
228 | } | |
229 | break; | |
230 | case LO_SUM: | |
231 | op[0] = XEXP (x, 0); | |
232 | st[1] = "+low("; | |
233 | op[1] = XEXP (x, 1); | |
234 | st[2] = ")"; | |
235 | break; | |
236 | case MINUS: | |
237 | op[0] = XEXP (x, 0); | |
238 | st[1] = "-"; | |
239 | op[1] = XEXP (x, 1); | |
240 | break; | |
241 | case COMPARE: | |
242 | fun = "cmp"; | |
243 | op[0] = XEXP (x, 0); | |
244 | op[1] = XEXP (x, 1); | |
245 | break; | |
246 | case NEG: | |
247 | st[0] = "-"; | |
248 | op[0] = XEXP (x, 0); | |
249 | break; | |
250 | case MULT: | |
251 | op[0] = XEXP (x, 0); | |
252 | st[1] = "*"; | |
253 | op[1] = XEXP (x, 1); | |
254 | break; | |
255 | case DIV: | |
256 | op[0] = XEXP (x, 0); | |
257 | st[1] = "/"; | |
258 | op[1] = XEXP (x, 1); | |
259 | break; | |
260 | case UDIV: | |
261 | fun = "udiv"; | |
262 | op[0] = XEXP (x, 0); | |
263 | op[1] = XEXP (x, 1); | |
264 | break; | |
265 | case MOD: | |
266 | op[0] = XEXP (x, 0); | |
267 | st[1] = "%"; | |
268 | op[1] = XEXP (x, 1); | |
269 | break; | |
270 | case UMOD: | |
271 | fun = "umod"; | |
272 | op[0] = XEXP (x, 0); | |
273 | op[1] = XEXP (x, 1); | |
274 | break; | |
275 | case SMIN: | |
276 | fun = "smin"; | |
277 | op[0] = XEXP (x, 0); | |
278 | op[1] = XEXP (x, 1); | |
279 | break; | |
280 | case SMAX: | |
281 | fun = "smax"; | |
282 | op[0] = XEXP (x, 0); | |
283 | op[1] = XEXP (x, 1); | |
284 | break; | |
285 | case UMIN: | |
286 | fun = "umin"; | |
287 | op[0] = XEXP (x, 0); | |
288 | op[1] = XEXP (x, 1); | |
289 | break; | |
290 | case UMAX: | |
291 | fun = "umax"; | |
292 | op[0] = XEXP (x, 0); | |
293 | op[1] = XEXP (x, 1); | |
294 | break; | |
295 | case NOT: | |
296 | st[0] = "!"; | |
297 | op[0] = XEXP (x, 0); | |
298 | break; | |
299 | case AND: | |
300 | op[0] = XEXP (x, 0); | |
301 | st[1] = "&"; | |
302 | op[1] = XEXP (x, 1); | |
303 | break; | |
304 | case IOR: | |
305 | op[0] = XEXP (x, 0); | |
306 | st[1] = "|"; | |
307 | op[1] = XEXP (x, 1); | |
308 | break; | |
309 | case XOR: | |
310 | op[0] = XEXP (x, 0); | |
311 | st[1] = "^"; | |
312 | op[1] = XEXP (x, 1); | |
313 | break; | |
314 | case ASHIFT: | |
315 | op[0] = XEXP (x, 0); | |
316 | st[1] = "<<"; | |
317 | op[1] = XEXP (x, 1); | |
318 | break; | |
319 | case LSHIFTRT: | |
320 | op[0] = XEXP (x, 0); | |
321 | st[1] = " 0>>"; | |
322 | op[1] = XEXP (x, 1); | |
323 | break; | |
324 | case ASHIFTRT: | |
325 | op[0] = XEXP (x, 0); | |
326 | st[1] = ">>"; | |
327 | op[1] = XEXP (x, 1); | |
328 | break; | |
329 | case ROTATE: | |
330 | op[0] = XEXP (x, 0); | |
331 | st[1] = "<-<"; | |
332 | op[1] = XEXP (x, 1); | |
333 | break; | |
334 | case ROTATERT: | |
335 | op[0] = XEXP (x, 0); | |
336 | st[1] = ">->"; | |
337 | op[1] = XEXP (x, 1); | |
338 | break; | |
339 | case ABS: | |
340 | fun = "abs"; | |
341 | op[0] = XEXP (x, 0); | |
342 | break; | |
343 | case SQRT: | |
344 | fun = "sqrt"; | |
345 | op[0] = XEXP (x, 0); | |
346 | break; | |
347 | case FFS: | |
348 | fun = "ffs"; | |
349 | op[0] = XEXP (x, 0); | |
350 | break; | |
351 | case EQ: | |
352 | op[0] = XEXP (x, 0); | |
353 | st[1] = "=="; | |
354 | op[1] = XEXP (x, 1); | |
355 | break; | |
356 | case NE: | |
357 | op[0] = XEXP (x, 0); | |
358 | st[1] = "!="; | |
359 | op[1] = XEXP (x, 1); | |
360 | break; | |
361 | case GT: | |
362 | op[0] = XEXP (x, 0); | |
363 | st[1] = ">"; | |
364 | op[1] = XEXP (x, 1); | |
365 | break; | |
366 | case GTU: | |
367 | fun = "gtu"; | |
368 | op[0] = XEXP (x, 0); | |
369 | op[1] = XEXP (x, 1); | |
370 | break; | |
371 | case LT: | |
372 | op[0] = XEXP (x, 0); | |
373 | st[1] = "<"; | |
374 | op[1] = XEXP (x, 1); | |
375 | break; | |
376 | case LTU: | |
377 | fun = "ltu"; | |
378 | op[0] = XEXP (x, 0); | |
379 | op[1] = XEXP (x, 1); | |
380 | break; | |
381 | case GE: | |
382 | op[0] = XEXP (x, 0); | |
383 | st[1] = ">="; | |
384 | op[1] = XEXP (x, 1); | |
385 | break; | |
386 | case GEU: | |
387 | fun = "geu"; | |
388 | op[0] = XEXP (x, 0); | |
389 | op[1] = XEXP (x, 1); | |
390 | break; | |
391 | case LE: | |
392 | op[0] = XEXP (x, 0); | |
393 | st[1] = "<="; | |
394 | op[1] = XEXP (x, 1); | |
395 | break; | |
396 | case LEU: | |
397 | fun = "leu"; | |
398 | op[0] = XEXP (x, 0); | |
399 | op[1] = XEXP (x, 1); | |
400 | break; | |
401 | case SIGN_EXTRACT: | |
402 | fun = (verbose) ? "sign_extract" : "sxt"; | |
403 | op[0] = XEXP (x, 0); | |
404 | op[1] = XEXP (x, 1); | |
405 | op[2] = XEXP (x, 2); | |
406 | break; | |
407 | case ZERO_EXTRACT: | |
408 | fun = (verbose) ? "zero_extract" : "zxt"; | |
409 | op[0] = XEXP (x, 0); | |
410 | op[1] = XEXP (x, 1); | |
411 | op[2] = XEXP (x, 2); | |
412 | break; | |
413 | case SIGN_EXTEND: | |
414 | fun = (verbose) ? "sign_extend" : "sxn"; | |
415 | op[0] = XEXP (x, 0); | |
416 | break; | |
417 | case ZERO_EXTEND: | |
418 | fun = (verbose) ? "zero_extend" : "zxn"; | |
419 | op[0] = XEXP (x, 0); | |
420 | break; | |
421 | case FLOAT_EXTEND: | |
422 | fun = (verbose) ? "float_extend" : "fxn"; | |
423 | op[0] = XEXP (x, 0); | |
424 | break; | |
425 | case TRUNCATE: | |
426 | fun = (verbose) ? "trunc" : "trn"; | |
427 | op[0] = XEXP (x, 0); | |
428 | break; | |
429 | case FLOAT_TRUNCATE: | |
430 | fun = (verbose) ? "float_trunc" : "ftr"; | |
431 | op[0] = XEXP (x, 0); | |
432 | break; | |
433 | case FLOAT: | |
434 | fun = (verbose) ? "float" : "flt"; | |
435 | op[0] = XEXP (x, 0); | |
436 | break; | |
437 | case UNSIGNED_FLOAT: | |
438 | fun = (verbose) ? "uns_float" : "ufl"; | |
439 | op[0] = XEXP (x, 0); | |
440 | break; | |
441 | case FIX: | |
442 | fun = "fix"; | |
443 | op[0] = XEXP (x, 0); | |
444 | break; | |
445 | case UNSIGNED_FIX: | |
446 | fun = (verbose) ? "uns_fix" : "ufx"; | |
447 | op[0] = XEXP (x, 0); | |
448 | break; | |
449 | case PRE_DEC: | |
450 | st[0] = "--"; | |
451 | op[0] = XEXP (x, 0); | |
452 | break; | |
453 | case PRE_INC: | |
454 | st[0] = "++"; | |
455 | op[0] = XEXP (x, 0); | |
456 | break; | |
457 | case POST_DEC: | |
458 | op[0] = XEXP (x, 0); | |
459 | st[1] = "--"; | |
460 | break; | |
461 | case POST_INC: | |
462 | op[0] = XEXP (x, 0); | |
463 | st[1] = "++"; | |
464 | break; | |
465 | case CALL: | |
466 | st[0] = "call "; | |
467 | op[0] = XEXP (x, 0); | |
468 | if (verbose) | |
469 | { | |
470 | st[1] = " argc:"; | |
471 | op[1] = XEXP (x, 1); | |
472 | } | |
473 | break; | |
474 | case IF_THEN_ELSE: | |
475 | st[0] = "{("; | |
476 | op[0] = XEXP (x, 0); | |
477 | st[1] = ")?"; | |
478 | op[1] = XEXP (x, 1); | |
479 | st[2] = ":"; | |
480 | op[2] = XEXP (x, 2); | |
481 | st[3] = "}"; | |
482 | break; | |
483 | case TRAP_IF: | |
484 | fun = "trap_if"; | |
485 | op[0] = TRAP_CONDITION (x); | |
486 | break; | |
21b8482a JJ |
487 | case PREFETCH: |
488 | fun = "prefetch"; | |
489 | op[0] = XEXP (x, 0); | |
490 | op[1] = XEXP (x, 1); | |
491 | op[2] = XEXP (x, 2); | |
492 | break; | |
c62c2659 BS |
493 | case UNSPEC: |
494 | case UNSPEC_VOLATILE: | |
495 | { | |
496 | cur = safe_concat (buf, cur, "unspec"); | |
497 | if (GET_CODE (x) == UNSPEC_VOLATILE) | |
498 | cur = safe_concat (buf, cur, "/v"); | |
499 | cur = safe_concat (buf, cur, "["); | |
500 | sep = ""; | |
501 | for (i = 0; i < XVECLEN (x, 0); i++) | |
502 | { | |
503 | print_pattern (tmp, XVECEXP (x, 0, i), verbose); | |
504 | cur = safe_concat (buf, cur, sep); | |
505 | cur = safe_concat (buf, cur, tmp); | |
506 | sep = ","; | |
507 | } | |
508 | cur = safe_concat (buf, cur, "] "); | |
509 | sprintf (tmp, "%d", XINT (x, 1)); | |
510 | cur = safe_concat (buf, cur, tmp); | |
511 | } | |
512 | break; | |
513 | default: | |
514 | /* If (verbose) debug_rtx (x); */ | |
515 | st[0] = GET_RTX_NAME (GET_CODE (x)); | |
516 | break; | |
517 | } | |
518 | ||
519 | /* Print this as a function? */ | |
520 | if (fun) | |
521 | { | |
522 | cur = safe_concat (buf, cur, fun); | |
523 | cur = safe_concat (buf, cur, "("); | |
524 | } | |
525 | ||
526 | for (i = 0; i < 4; i++) | |
527 | { | |
528 | if (st[i]) | |
529 | cur = safe_concat (buf, cur, st[i]); | |
530 | ||
531 | if (op[i]) | |
532 | { | |
533 | if (fun && i != 0) | |
534 | cur = safe_concat (buf, cur, ","); | |
535 | ||
536 | print_value (tmp, op[i], verbose); | |
537 | cur = safe_concat (buf, cur, tmp); | |
538 | } | |
539 | } | |
540 | ||
541 | if (fun) | |
542 | cur = safe_concat (buf, cur, ")"); | |
543 | } /* print_exp */ | |
544 | ||
545 | /* Prints rtxes, I customly classified as values. They're constants, | |
546 | registers, labels, symbols and memory accesses. */ | |
547 | ||
548 | static void | |
549 | print_value (buf, x, verbose) | |
550 | char *buf; | |
551 | rtx x; | |
552 | int verbose; | |
553 | { | |
554 | char t[BUF_LEN]; | |
555 | char *cur = buf; | |
556 | ||
557 | switch (GET_CODE (x)) | |
558 | { | |
559 | case CONST_INT: | |
560 | sprintf (t, HOST_WIDE_INT_PRINT_HEX, INTVAL (x)); | |
561 | cur = safe_concat (buf, cur, t); | |
562 | break; | |
563 | case CONST_DOUBLE: | |
b3ae1ccd | 564 | if (FLOAT_MODE_P (GET_MODE (x))) |
da6eec72 | 565 | real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1); |
b3ae1ccd RH |
566 | else |
567 | sprintf (t, "<0x%lx,0x%lx>", (long) XWINT (x, 2), (long) XWINT (x, 3)); | |
c62c2659 BS |
568 | cur = safe_concat (buf, cur, t); |
569 | break; | |
570 | case CONST_STRING: | |
571 | cur = safe_concat (buf, cur, "\""); | |
572 | cur = safe_concat (buf, cur, XSTR (x, 0)); | |
573 | cur = safe_concat (buf, cur, "\""); | |
574 | break; | |
575 | case SYMBOL_REF: | |
576 | cur = safe_concat (buf, cur, "`"); | |
577 | cur = safe_concat (buf, cur, XSTR (x, 0)); | |
578 | cur = safe_concat (buf, cur, "'"); | |
579 | break; | |
580 | case LABEL_REF: | |
581 | sprintf (t, "L%d", INSN_UID (XEXP (x, 0))); | |
582 | cur = safe_concat (buf, cur, t); | |
583 | break; | |
584 | case CONST: | |
585 | print_value (t, XEXP (x, 0), verbose); | |
586 | cur = safe_concat (buf, cur, "const("); | |
587 | cur = safe_concat (buf, cur, t); | |
588 | cur = safe_concat (buf, cur, ")"); | |
589 | break; | |
590 | case HIGH: | |
591 | print_value (t, XEXP (x, 0), verbose); | |
592 | cur = safe_concat (buf, cur, "high("); | |
593 | cur = safe_concat (buf, cur, t); | |
594 | cur = safe_concat (buf, cur, ")"); | |
595 | break; | |
596 | case REG: | |
597 | if (REGNO (x) < FIRST_PSEUDO_REGISTER) | |
598 | { | |
599 | int c = reg_names[REGNO (x)][0]; | |
0df6c2c7 | 600 | if (ISDIGIT (c)) |
c62c2659 BS |
601 | cur = safe_concat (buf, cur, "%"); |
602 | ||
603 | cur = safe_concat (buf, cur, reg_names[REGNO (x)]); | |
604 | } | |
605 | else | |
606 | { | |
607 | sprintf (t, "r%d", REGNO (x)); | |
608 | cur = safe_concat (buf, cur, t); | |
609 | } | |
610 | break; | |
611 | case SUBREG: | |
612 | print_value (t, SUBREG_REG (x), verbose); | |
613 | cur = safe_concat (buf, cur, t); | |
ddef6bc7 | 614 | sprintf (t, "#%d", SUBREG_BYTE (x)); |
c62c2659 BS |
615 | cur = safe_concat (buf, cur, t); |
616 | break; | |
617 | case SCRATCH: | |
618 | cur = safe_concat (buf, cur, "scratch"); | |
619 | break; | |
620 | case CC0: | |
621 | cur = safe_concat (buf, cur, "cc0"); | |
622 | break; | |
623 | case PC: | |
624 | cur = safe_concat (buf, cur, "pc"); | |
625 | break; | |
626 | case MEM: | |
627 | print_value (t, XEXP (x, 0), verbose); | |
628 | cur = safe_concat (buf, cur, "["); | |
629 | cur = safe_concat (buf, cur, t); | |
630 | cur = safe_concat (buf, cur, "]"); | |
631 | break; | |
632 | default: | |
633 | print_exp (t, x, verbose); | |
634 | cur = safe_concat (buf, cur, t); | |
635 | break; | |
636 | } | |
637 | } /* print_value */ | |
638 | ||
639 | /* The next step in insn detalization, its pattern recognition. */ | |
640 | ||
641 | static void | |
642 | print_pattern (buf, x, verbose) | |
643 | char *buf; | |
644 | rtx x; | |
645 | int verbose; | |
646 | { | |
647 | char t1[BUF_LEN], t2[BUF_LEN], t3[BUF_LEN]; | |
648 | ||
649 | switch (GET_CODE (x)) | |
650 | { | |
651 | case SET: | |
652 | print_value (t1, SET_DEST (x), verbose); | |
653 | print_value (t2, SET_SRC (x), verbose); | |
654 | sprintf (buf, "%s=%s", t1, t2); | |
655 | break; | |
656 | case RETURN: | |
657 | sprintf (buf, "return"); | |
658 | break; | |
659 | case CALL: | |
660 | print_exp (buf, x, verbose); | |
661 | break; | |
662 | case CLOBBER: | |
663 | print_value (t1, XEXP (x, 0), verbose); | |
664 | sprintf (buf, "clobber %s", t1); | |
665 | break; | |
666 | case USE: | |
667 | print_value (t1, XEXP (x, 0), verbose); | |
668 | sprintf (buf, "use %s", t1); | |
669 | break; | |
670 | case COND_EXEC: | |
671 | if (GET_CODE (COND_EXEC_TEST (x)) == NE | |
672 | && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) | |
673 | print_value (t1, XEXP (COND_EXEC_TEST (x), 0), verbose); | |
674 | else if (GET_CODE (COND_EXEC_TEST (x)) == EQ | |
786de7eb KH |
675 | && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) |
676 | { | |
c62c2659 BS |
677 | t1[0] = '!'; |
678 | print_value (t1 + 1, XEXP (COND_EXEC_TEST (x), 0), verbose); | |
679 | } | |
680 | else | |
786de7eb | 681 | print_value (t1, COND_EXEC_TEST (x), verbose); |
c62c2659 BS |
682 | print_pattern (t2, COND_EXEC_CODE (x), verbose); |
683 | sprintf (buf, "(%s) %s", t1, t2); | |
684 | break; | |
685 | case PARALLEL: | |
686 | { | |
687 | int i; | |
688 | ||
689 | sprintf (t1, "{"); | |
690 | for (i = 0; i < XVECLEN (x, 0); i++) | |
691 | { | |
692 | print_pattern (t2, XVECEXP (x, 0, i), verbose); | |
693 | sprintf (t3, "%s%s;", t1, t2); | |
694 | strcpy (t1, t3); | |
695 | } | |
696 | sprintf (buf, "%s}", t1); | |
697 | } | |
698 | break; | |
699 | case SEQUENCE: | |
2f937369 DM |
700 | /* Should never see SEQUENCE codes until after reorg. */ |
701 | abort (); | |
c62c2659 BS |
702 | break; |
703 | case ASM_INPUT: | |
704 | sprintf (buf, "asm {%s}", XSTR (x, 0)); | |
705 | break; | |
706 | case ADDR_VEC: | |
707 | break; | |
708 | case ADDR_DIFF_VEC: | |
709 | print_value (buf, XEXP (x, 0), verbose); | |
710 | break; | |
711 | case TRAP_IF: | |
712 | print_value (t1, TRAP_CONDITION (x), verbose); | |
713 | sprintf (buf, "trap_if %s", t1); | |
714 | break; | |
715 | case UNSPEC: | |
716 | { | |
717 | int i; | |
718 | ||
719 | sprintf (t1, "unspec{"); | |
720 | for (i = 0; i < XVECLEN (x, 0); i++) | |
721 | { | |
722 | print_pattern (t2, XVECEXP (x, 0, i), verbose); | |
723 | sprintf (t3, "%s%s;", t1, t2); | |
724 | strcpy (t1, t3); | |
725 | } | |
726 | sprintf (buf, "%s}", t1); | |
727 | } | |
728 | break; | |
729 | case UNSPEC_VOLATILE: | |
730 | { | |
731 | int i; | |
732 | ||
733 | sprintf (t1, "unspec/v{"); | |
734 | for (i = 0; i < XVECLEN (x, 0); i++) | |
735 | { | |
736 | print_pattern (t2, XVECEXP (x, 0, i), verbose); | |
737 | sprintf (t3, "%s%s;", t1, t2); | |
738 | strcpy (t1, t3); | |
739 | } | |
740 | sprintf (buf, "%s}", t1); | |
741 | } | |
742 | break; | |
743 | default: | |
744 | print_value (buf, x, verbose); | |
745 | } | |
746 | } /* print_pattern */ | |
747 | ||
748 | /* This is the main function in rtl visualization mechanism. It | |
749 | accepts an rtx and tries to recognize it as an insn, then prints it | |
750 | properly in human readable form, resembling assembler mnemonics. | |
751 | For every insn it prints its UID and BB the insn belongs too. | |
752 | (Probably the last "option" should be extended somehow, since it | |
753 | depends now on sched.c inner variables ...) */ | |
754 | ||
6d0de005 | 755 | void |
c62c2659 BS |
756 | print_insn (buf, x, verbose) |
757 | char *buf; | |
758 | rtx x; | |
759 | int verbose; | |
760 | { | |
761 | char t[BUF_LEN]; | |
762 | rtx insn = x; | |
763 | ||
764 | switch (GET_CODE (x)) | |
765 | { | |
766 | case INSN: | |
767 | print_pattern (t, PATTERN (x), verbose); | |
768 | if (verbose) | |
769 | sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1), | |
770 | t); | |
771 | else | |
772 | sprintf (buf, "%-4d %s", INSN_UID (x), t); | |
773 | break; | |
774 | case JUMP_INSN: | |
775 | print_pattern (t, PATTERN (x), verbose); | |
776 | if (verbose) | |
777 | sprintf (buf, "%s: jump %s", (*current_sched_info->print_insn) (x, 1), | |
778 | t); | |
779 | else | |
780 | sprintf (buf, "%-4d %s", INSN_UID (x), t); | |
781 | break; | |
782 | case CALL_INSN: | |
783 | x = PATTERN (insn); | |
784 | if (GET_CODE (x) == PARALLEL) | |
785 | { | |
786 | x = XVECEXP (x, 0, 0); | |
787 | print_pattern (t, x, verbose); | |
788 | } | |
789 | else | |
790 | strcpy (t, "call <...>"); | |
791 | if (verbose) | |
792 | sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1), t); | |
793 | else | |
794 | sprintf (buf, "%-4d %s", INSN_UID (insn), t); | |
795 | break; | |
796 | case CODE_LABEL: | |
797 | sprintf (buf, "L%d:", INSN_UID (x)); | |
798 | break; | |
799 | case BARRIER: | |
800 | sprintf (buf, "i% 4d: barrier", INSN_UID (x)); | |
801 | break; | |
802 | case NOTE: | |
803 | if (NOTE_LINE_NUMBER (x) > 0) | |
804 | sprintf (buf, "%4d note \"%s\" %d", INSN_UID (x), | |
805 | NOTE_SOURCE_FILE (x), NOTE_LINE_NUMBER (x)); | |
806 | else | |
807 | sprintf (buf, "%4d %s", INSN_UID (x), | |
808 | GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (x))); | |
809 | break; | |
810 | default: | |
811 | if (verbose) | |
812 | { | |
813 | sprintf (buf, "Not an INSN at all\n"); | |
814 | debug_rtx (x); | |
815 | } | |
816 | else | |
817 | sprintf (buf, "i%-4d <What?>", INSN_UID (x)); | |
818 | } | |
819 | } /* print_insn */ | |
820 | ||
fae15c93 VM |
821 | /* Print visualization debugging info. The scheduler using only DFA |
822 | description should never use the following function. */ | |
c62c2659 BS |
823 | |
824 | void | |
825 | print_block_visualization (s) | |
826 | const char *s; | |
827 | { | |
828 | int unit, i; | |
829 | ||
830 | /* Print header. */ | |
831 | fprintf (sched_dump, "\n;; ==================== scheduling visualization %s \n", s); | |
832 | ||
833 | /* Print names of units. */ | |
834 | fprintf (sched_dump, ";; %-8s", "clock"); | |
835 | for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++) | |
836 | if (function_units[unit].bitmask & target_units) | |
837 | for (i = 0; i < function_units[unit].multiplicity; i++) | |
838 | fprintf (sched_dump, " %-33s", function_units[unit].name); | |
839 | fprintf (sched_dump, " %-8s\n", "no-unit"); | |
840 | ||
841 | fprintf (sched_dump, ";; %-8s", "====="); | |
842 | for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++) | |
843 | if (function_units[unit].bitmask & target_units) | |
844 | for (i = 0; i < function_units[unit].multiplicity; i++) | |
845 | fprintf (sched_dump, " %-33s", "=============================="); | |
846 | fprintf (sched_dump, " %-8s\n", "======="); | |
847 | ||
848 | /* Print insns in each cycle. */ | |
849 | fprintf (sched_dump, "%s\n", visual_tbl); | |
850 | } | |
851 | ||
852 | /* Print insns in the 'no_unit' column of visualization. */ | |
853 | ||
854 | void | |
855 | visualize_no_unit (insn) | |
856 | rtx insn; | |
857 | { | |
b1b6b0cb GS |
858 | if (n_vis_no_unit < MAX_VISUAL_NO_UNIT) |
859 | { | |
860 | vis_no_unit[n_vis_no_unit] = insn; | |
861 | n_vis_no_unit++; | |
862 | } | |
c62c2659 BS |
863 | } |
864 | ||
865 | /* Print insns scheduled in clock, for visualization. */ | |
866 | ||
867 | void | |
868 | visualize_scheduled_insns (clock) | |
869 | int clock; | |
870 | { | |
871 | int i, unit; | |
872 | ||
873 | /* If no more room, split table into two. */ | |
874 | if (n_visual_lines >= MAX_VISUAL_LINES) | |
875 | { | |
876 | print_block_visualization ("(incomplete)"); | |
877 | init_block_visualization (); | |
878 | } | |
879 | ||
880 | n_visual_lines++; | |
881 | ||
882 | sprintf (visual_tbl + strlen (visual_tbl), ";; %-8d", clock); | |
883 | for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++) | |
884 | if (function_units[unit].bitmask & target_units) | |
885 | for (i = 0; i < function_units[unit].multiplicity; i++) | |
886 | { | |
887 | int instance = unit + i * FUNCTION_UNITS_SIZE; | |
888 | rtx insn = get_unit_last_insn (instance); | |
889 | ||
890 | /* Print insns that still keep the unit busy. */ | |
891 | if (insn | |
892 | && actual_hazard_this_instance (unit, instance, insn, clock, 0)) | |
893 | { | |
894 | char str[BUF_LEN]; | |
895 | print_insn (str, insn, 0); | |
896 | str[INSN_LEN] = '\0'; | |
897 | sprintf (visual_tbl + strlen (visual_tbl), " %-33s", str); | |
898 | } | |
899 | else | |
900 | sprintf (visual_tbl + strlen (visual_tbl), " %-33s", "------------------------------"); | |
901 | } | |
902 | ||
903 | /* Print insns that are not assigned to any unit. */ | |
904 | for (i = 0; i < n_vis_no_unit; i++) | |
905 | sprintf (visual_tbl + strlen (visual_tbl), " %-8d", | |
906 | INSN_UID (vis_no_unit[i])); | |
907 | n_vis_no_unit = 0; | |
908 | ||
909 | sprintf (visual_tbl + strlen (visual_tbl), "\n"); | |
910 | } | |
911 | ||
912 | /* Print stalled cycles. */ | |
913 | ||
914 | void | |
915 | visualize_stall_cycles (stalls) | |
916 | int stalls; | |
917 | { | |
83182544 | 918 | static const char *const prefix = ";; "; |
4c42e347 AO |
919 | const char *suffix = "\n"; |
920 | char *p; | |
c62c2659 BS |
921 | |
922 | /* If no more room, split table into two. */ | |
923 | if (n_visual_lines >= MAX_VISUAL_LINES) | |
924 | { | |
925 | print_block_visualization ("(incomplete)"); | |
926 | init_block_visualization (); | |
927 | } | |
928 | ||
929 | n_visual_lines++; | |
930 | ||
4c42e347 AO |
931 | p = visual_tbl + strlen (visual_tbl); |
932 | strcpy (p, prefix); | |
933 | p += strlen (prefix); | |
934 | ||
cf403648 | 935 | if ((unsigned) stalls > |
4c42e347 AO |
936 | visual_tbl_line_length - strlen (prefix) - strlen (suffix)) |
937 | { | |
938 | suffix = "[...]\n"; | |
939 | stalls = visual_tbl_line_length - strlen (prefix) - strlen (suffix); | |
940 | } | |
941 | ||
942 | memset (p, '.', stalls); | |
943 | p += stalls; | |
944 | ||
945 | strcpy (p, suffix); | |
c62c2659 BS |
946 | } |
947 | ||
948 | /* Allocate data used for visualization during scheduling. */ | |
949 | ||
950 | void | |
951 | visualize_alloc () | |
952 | { | |
953 | visual_tbl = xmalloc (get_visual_tbl_length ()); | |
954 | } | |
955 | ||
956 | /* Free data used for visualization. */ | |
957 | ||
958 | void | |
959 | visualize_free () | |
960 | { | |
961 | free (visual_tbl); | |
962 | } | |
f56887a7 | 963 | #endif |