]>
Commit | Line | Data |
---|---|---|
e855c69d | 1 | /* Instruction scheduling pass. Log dumping infrastructure. |
7adcbafe | 2 | Copyright (C) 2006-2022 Free Software Foundation, Inc. |
e855c69d AB |
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 | #include "config.h" | |
21 | #include "system.h" | |
22 | #include "coretypes.h" | |
c7131fb2 | 23 | #include "backend.h" |
e855c69d | 24 | #include "rtl.h" |
c7131fb2 | 25 | #include "df.h" |
e855c69d | 26 | #include "insn-attr.h" |
e855c69d | 27 | #include "cselib.h" |
dfb0e60d AB |
28 | |
29 | #ifdef INSN_SCHEDULING | |
c7131fb2 AM |
30 | #include "regset.h" |
31 | #include "sched-int.h" | |
32 | #include "cfgloop.h" | |
e855c69d AB |
33 | #include "sel-sched-ir.h" |
34 | #include "sel-sched-dump.h" | |
013a8899 | 35 | #include "print-rtl.h" |
e855c69d AB |
36 | \f |
37 | ||
38 | /* These variables control high-level pretty printing. */ | |
39 | static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS; | |
40 | static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS; | |
41 | ||
42 | /* True when a cfg should be dumped. */ | |
43 | static bool sel_dump_cfg_p; | |
44 | ||
45 | /* Variables that are used to build the cfg dump file name. */ | |
46 | static const char * const sel_debug_cfg_root = "./"; | |
47 | static const char * const sel_debug_cfg_root_postfix_default = ""; | |
48 | static const char *sel_debug_cfg_root_postfix = ""; | |
49 | static int sel_dump_cfg_fileno = -1; | |
50 | static int sel_debug_cfg_fileno = -1; | |
51 | ||
52 | /* When this flag is on, we are dumping to the .dot file. | |
53 | When it is off, we are dumping to log. | |
54 | This is useful to differentiate formatting between log and .dot | |
55 | files. */ | |
56 | bool sched_dump_to_dot_p = false; | |
57 | ||
58 | /* Controls how insns from a fence list should be dumped. */ | |
59 | static int dump_flist_insn_flags = (DUMP_INSN_UID | DUMP_INSN_BBN | |
60 | | DUMP_INSN_SEQNO); | |
61 | \f | |
62 | ||
63 | /* The variable used to hold the value of sched_dump when temporarily | |
64 | switching dump output to the other source, e.g. the .dot file. */ | |
65 | static FILE *saved_sched_dump = NULL; | |
66 | ||
67 | /* Switch sched_dump to TO. It must not be called twice. */ | |
68 | static void | |
69 | switch_dump (FILE *to) | |
70 | { | |
71 | gcc_assert (saved_sched_dump == NULL); | |
b8698a0f | 72 | |
e855c69d AB |
73 | saved_sched_dump = sched_dump; |
74 | sched_dump = to; | |
75 | } | |
76 | ||
77 | /* Restore previously switched dump. */ | |
78 | static void | |
79 | restore_dump (void) | |
80 | { | |
81 | sched_dump = saved_sched_dump; | |
82 | saved_sched_dump = NULL; | |
83 | } | |
84 | \f | |
85 | ||
b8698a0f | 86 | /* Functions for dumping instructions, av sets, and exprs. */ |
e855c69d AB |
87 | |
88 | /* Default flags for dumping insns. */ | |
242387fa | 89 | static int dump_insn_rtx_flags = DUMP_INSN_RTX_UID | DUMP_INSN_RTX_PATTERN; |
e855c69d AB |
90 | |
91 | /* Default flags for dumping vinsns. */ | |
92 | static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE | |
93 | | DUMP_VINSN_COUNT); | |
94 | ||
95 | /* Default flags for dumping expressions. */ | |
96 | static int dump_expr_flags = DUMP_EXPR_ALL; | |
97 | ||
98 | /* Default flags for dumping insns when debugging. */ | |
99 | static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL; | |
100 | ||
101 | /* Default flags for dumping vinsns when debugging. */ | |
102 | static int debug_vinsn_flags = DUMP_VINSN_ALL; | |
103 | ||
104 | /* Default flags for dumping expressions when debugging. */ | |
105 | static int debug_expr_flags = DUMP_EXPR_ALL; | |
106 | ||
107 | /* Controls how an insn from stream should be dumped when debugging. */ | |
108 | static int debug_insn_flags = DUMP_INSN_ALL; | |
109 | ||
110 | /* Print an rtx X. */ | |
111 | void | |
112 | sel_print_rtl (rtx x) | |
113 | { | |
114 | print_rtl_single (sched_dump, x); | |
115 | } | |
116 | ||
117 | /* Dump insn INSN honoring FLAGS. */ | |
118 | void | |
119 | dump_insn_rtx_1 (rtx insn, int flags) | |
120 | { | |
121 | int all; | |
122 | ||
123 | /* flags == -1 also means dumping all. */ | |
5de73c05 | 124 | all = (flags & 1); |
e855c69d AB |
125 | if (all) |
126 | flags |= DUMP_INSN_RTX_ALL; | |
127 | ||
128 | sel_print ("("); | |
129 | ||
130 | if (flags & DUMP_INSN_RTX_UID) | |
131 | sel_print ("%d;", INSN_UID (insn)); | |
132 | ||
133 | if (flags & DUMP_INSN_RTX_PATTERN) | |
242387fa | 134 | sel_print ("%s;", str_pattern_slim (PATTERN (insn))); |
e855c69d AB |
135 | |
136 | if (flags & DUMP_INSN_RTX_BBN) | |
137 | { | |
138 | basic_block bb = BLOCK_FOR_INSN (insn); | |
139 | ||
140 | sel_print ("bb:%d;", bb != NULL ? bb->index : -1); | |
141 | } | |
142 | ||
143 | sel_print (")"); | |
144 | } | |
145 | ||
146 | ||
147 | /* Dump INSN with default flags. */ | |
148 | void | |
149 | dump_insn_rtx (rtx insn) | |
150 | { | |
151 | dump_insn_rtx_1 (insn, dump_insn_rtx_flags); | |
152 | } | |
153 | ||
154 | ||
155 | /* Dump INSN to stderr. */ | |
24e47c76 | 156 | DEBUG_FUNCTION void |
e855c69d AB |
157 | debug_insn_rtx (rtx insn) |
158 | { | |
159 | switch_dump (stderr); | |
160 | dump_insn_rtx_1 (insn, debug_insn_rtx_flags); | |
161 | sel_print ("\n"); | |
162 | restore_dump (); | |
163 | } | |
164 | ||
165 | /* Dump vinsn VI honoring flags. */ | |
166 | void | |
167 | dump_vinsn_1 (vinsn_t vi, int flags) | |
168 | { | |
169 | int all; | |
170 | ||
171 | /* flags == -1 also means dumping all. */ | |
172 | all = flags & 1; | |
173 | if (all) | |
174 | flags |= DUMP_VINSN_ALL; | |
175 | ||
176 | sel_print ("("); | |
177 | ||
178 | if (flags & DUMP_VINSN_INSN_RTX) | |
179 | dump_insn_rtx_1 (VINSN_INSN_RTX (vi), dump_insn_rtx_flags | all); | |
180 | ||
181 | if (flags & DUMP_VINSN_TYPE) | |
182 | sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi))); | |
183 | ||
184 | if (flags & DUMP_VINSN_COUNT) | |
185 | sel_print ("count:%d;", VINSN_COUNT (vi)); | |
186 | ||
187 | if (flags & DUMP_VINSN_COST) | |
188 | { | |
189 | int cost = vi->cost; | |
190 | ||
191 | if (cost != -1) | |
192 | sel_print ("cost:%d;", cost); | |
193 | } | |
194 | ||
195 | sel_print (")"); | |
196 | } | |
197 | ||
198 | /* Dump vinsn VI with default flags. */ | |
199 | void | |
200 | dump_vinsn (vinsn_t vi) | |
201 | { | |
202 | dump_vinsn_1 (vi, dump_vinsn_flags); | |
203 | } | |
204 | ||
7b3b6ae4 LC |
205 | DEBUG_FUNCTION void |
206 | debug (vinsn_def &ref) | |
207 | { | |
208 | switch_dump (stderr); | |
209 | dump_vinsn_1 (&ref, dump_vinsn_flags); | |
210 | sel_print ("\n"); | |
211 | restore_dump (); | |
212 | } | |
213 | ||
214 | DEBUG_FUNCTION void | |
215 | debug (vinsn_def *ptr) | |
216 | { | |
217 | if (ptr) | |
218 | debug (*ptr); | |
219 | else | |
220 | fprintf (stderr, "<nil>\n"); | |
221 | } | |
222 | ||
223 | DEBUG_FUNCTION void | |
224 | debug_verbose (vinsn_def &ref) | |
225 | { | |
226 | switch_dump (stderr); | |
227 | dump_vinsn_1 (&ref, debug_vinsn_flags); | |
228 | sel_print ("\n"); | |
229 | restore_dump (); | |
230 | } | |
231 | ||
232 | DEBUG_FUNCTION void | |
233 | debug_verbose (vinsn_def *ptr) | |
234 | { | |
235 | if (ptr) | |
236 | debug (*ptr); | |
237 | else | |
238 | fprintf (stderr, "<nil>\n"); | |
239 | } | |
240 | ||
e855c69d | 241 | /* Dump vinsn VI to stderr. */ |
24e47c76 | 242 | DEBUG_FUNCTION void |
e855c69d AB |
243 | debug_vinsn (vinsn_t vi) |
244 | { | |
245 | switch_dump (stderr); | |
246 | dump_vinsn_1 (vi, debug_vinsn_flags); | |
b8698a0f | 247 | sel_print ("\n"); |
e855c69d AB |
248 | restore_dump (); |
249 | } | |
250 | ||
251 | /* Dump EXPR honoring flags. */ | |
252 | void | |
253 | dump_expr_1 (expr_t expr, int flags) | |
254 | { | |
255 | int all; | |
256 | ||
257 | /* flags == -1 also means dumping all. */ | |
258 | all = flags & 1; | |
259 | if (all) | |
260 | flags |= DUMP_EXPR_ALL; | |
261 | ||
262 | sel_print ("["); | |
263 | ||
264 | if (flags & DUMP_EXPR_VINSN) | |
265 | dump_vinsn_1 (EXPR_VINSN (expr), dump_vinsn_flags | all); | |
266 | ||
267 | if (flags & DUMP_EXPR_SPEC) | |
268 | { | |
269 | int spec = EXPR_SPEC (expr); | |
270 | ||
271 | if (spec != 0) | |
272 | sel_print ("spec:%d;", spec); | |
273 | } | |
274 | ||
275 | if (flags & DUMP_EXPR_USEFULNESS) | |
276 | { | |
277 | int use = EXPR_USEFULNESS (expr); | |
278 | ||
279 | if (use != REG_BR_PROB_BASE) | |
280 | sel_print ("use:%d;", use); | |
281 | } | |
282 | ||
283 | if (flags & DUMP_EXPR_PRIORITY) | |
284 | sel_print ("prio:%d;", EXPR_PRIORITY (expr)); | |
285 | ||
286 | if (flags & DUMP_EXPR_SCHED_TIMES) | |
287 | { | |
288 | int times = EXPR_SCHED_TIMES (expr); | |
289 | ||
290 | if (times != 0) | |
291 | sel_print ("times:%d;", times); | |
292 | } | |
293 | ||
294 | if (flags & DUMP_EXPR_SPEC_DONE_DS) | |
295 | { | |
296 | ds_t spec_done_ds = EXPR_SPEC_DONE_DS (expr); | |
297 | ||
298 | if (spec_done_ds != 0) | |
299 | sel_print ("ds:%d;", spec_done_ds); | |
300 | } | |
301 | ||
302 | if (flags & DUMP_EXPR_ORIG_BB) | |
303 | { | |
304 | int orig_bb = EXPR_ORIG_BB_INDEX (expr); | |
305 | ||
306 | if (orig_bb != 0) | |
307 | sel_print ("orig_bb:%d;", orig_bb); | |
308 | } | |
b8698a0f | 309 | |
e855c69d AB |
310 | if (EXPR_TARGET_AVAILABLE (expr) < 1) |
311 | sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr)); | |
312 | sel_print ("]"); | |
313 | } | |
314 | ||
315 | /* Dump expression EXPR with default flags. */ | |
316 | void | |
317 | dump_expr (expr_t expr) | |
318 | { | |
319 | dump_expr_1 (expr, dump_expr_flags); | |
320 | } | |
321 | ||
322 | /* Dump expression EXPR to stderr. */ | |
24e47c76 | 323 | DEBUG_FUNCTION void |
e855c69d AB |
324 | debug_expr (expr_t expr) |
325 | { | |
326 | switch_dump (stderr); | |
327 | dump_expr_1 (expr, debug_expr_flags); | |
328 | sel_print ("\n"); | |
329 | restore_dump (); | |
330 | } | |
331 | ||
7b3b6ae4 LC |
332 | /* Dump expression REF. */ |
333 | ||
334 | DEBUG_FUNCTION void | |
335 | debug (expr_def &ref) | |
336 | { | |
337 | switch_dump (stderr); | |
338 | dump_expr_1 (&ref, 0); | |
339 | sel_print ("\n"); | |
340 | restore_dump (); | |
341 | } | |
342 | ||
343 | DEBUG_FUNCTION void | |
344 | debug (expr_def *ptr) | |
345 | { | |
346 | if (ptr) | |
347 | debug (*ptr); | |
348 | else | |
349 | fprintf (stderr, "<nil>\n"); | |
350 | } | |
351 | ||
352 | /* Dump expression REF verbosely. */ | |
353 | ||
354 | DEBUG_FUNCTION void | |
355 | debug_verbose (expr_def &ref) | |
356 | { | |
357 | switch_dump (stderr); | |
358 | dump_expr_1 (&ref, DUMP_EXPR_ALL); | |
359 | sel_print ("\n"); | |
360 | restore_dump (); | |
361 | } | |
362 | ||
363 | DEBUG_FUNCTION void | |
364 | debug_verbose (expr_def *ptr) | |
365 | { | |
366 | if (ptr) | |
367 | debug_verbose (*ptr); | |
368 | else | |
369 | fprintf (stderr, "<nil>\n"); | |
370 | } | |
371 | ||
e855c69d AB |
372 | /* Dump insn I honoring FLAGS. */ |
373 | void | |
374 | dump_insn_1 (insn_t i, int flags) | |
375 | { | |
376 | int all; | |
377 | ||
378 | all = flags & 1; | |
379 | if (all) | |
380 | flags |= DUMP_INSN_ALL; | |
381 | ||
382 | if (!sched_dump_to_dot_p) | |
383 | sel_print ("("); | |
384 | ||
385 | if (flags & DUMP_INSN_EXPR) | |
386 | { | |
387 | dump_expr_1 (INSN_EXPR (i), dump_expr_flags | all); | |
388 | sel_print (";"); | |
389 | } | |
390 | else if (flags & DUMP_INSN_PATTERN) | |
391 | { | |
392 | dump_insn_rtx_1 (i, DUMP_INSN_RTX_PATTERN | all); | |
393 | sel_print (";"); | |
394 | } | |
395 | else if (flags & DUMP_INSN_UID) | |
396 | sel_print ("uid:%d;", INSN_UID (i)); | |
397 | ||
398 | if (flags & DUMP_INSN_SEQNO) | |
399 | sel_print ("seqno:%d;", INSN_SEQNO (i)); | |
400 | ||
401 | if (flags & DUMP_INSN_SCHED_CYCLE) | |
402 | { | |
403 | int cycle = INSN_SCHED_CYCLE (i); | |
404 | ||
405 | if (cycle != 0) | |
406 | sel_print ("cycle:%d;", cycle); | |
407 | } | |
408 | ||
409 | if (!sched_dump_to_dot_p) | |
410 | sel_print (")"); | |
411 | } | |
412 | ||
413 | /* Dump insn I with default flags. */ | |
414 | void | |
415 | dump_insn (insn_t i) | |
416 | { | |
417 | dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE); | |
418 | } | |
419 | ||
420 | /* Dump INSN to stderr. */ | |
24e47c76 | 421 | DEBUG_FUNCTION void |
e855c69d AB |
422 | debug_insn (insn_t insn) |
423 | { | |
424 | switch_dump (stderr); | |
425 | dump_insn_1 (insn, debug_insn_flags); | |
426 | sel_print ("\n"); | |
427 | restore_dump (); | |
428 | } | |
429 | ||
430 | /* Dumps av_set AV. */ | |
431 | void | |
432 | dump_av_set (av_set_t av) | |
433 | { | |
434 | av_set_iterator i; | |
435 | expr_t expr; | |
b8698a0f | 436 | |
e855c69d AB |
437 | if (!sched_dump_to_dot_p) |
438 | sel_print ("{"); | |
b8698a0f | 439 | |
e855c69d AB |
440 | FOR_EACH_EXPR (expr, i, av) |
441 | { | |
442 | dump_expr (expr); | |
443 | if (!sched_dump_to_dot_p) | |
444 | sel_print (" "); | |
445 | else | |
446 | sel_print ("\n"); | |
447 | } | |
b8698a0f | 448 | |
e855c69d AB |
449 | if (!sched_dump_to_dot_p) |
450 | sel_print ("}"); | |
451 | } | |
452 | ||
453 | /* Dumps lvset LV. */ | |
454 | void | |
455 | dump_lv_set (regset lv) | |
456 | { | |
457 | sel_print ("{"); | |
458 | ||
e53b6e56 | 459 | /* This code was adapted from cfg.cc: dump_regset (). */ |
e855c69d AB |
460 | if (lv == NULL) |
461 | sel_print ("nil"); | |
462 | else | |
463 | { | |
464 | unsigned i; | |
465 | reg_set_iterator rsi; | |
466 | int count = 0; | |
b8698a0f | 467 | |
e855c69d AB |
468 | EXECUTE_IF_SET_IN_REG_SET (lv, 0, i, rsi) |
469 | { | |
470 | sel_print (" %d", i); | |
471 | if (i < FIRST_PSEUDO_REGISTER) | |
472 | { | |
473 | sel_print (" [%s]", reg_names[i]); | |
474 | ++count; | |
475 | } | |
b8698a0f | 476 | |
e855c69d | 477 | ++count; |
b8698a0f | 478 | |
e855c69d AB |
479 | if (sched_dump_to_dot_p && count == 12) |
480 | { | |
481 | count = 0; | |
482 | sel_print ("\n"); | |
483 | } | |
484 | } | |
485 | } | |
b8698a0f | 486 | |
e855c69d AB |
487 | sel_print ("}\n"); |
488 | } | |
489 | ||
490 | /* Dumps a list of instructions pointed to by P. */ | |
491 | static void | |
492 | dump_ilist (ilist_t p) | |
493 | { | |
494 | while (p) | |
495 | { | |
496 | dump_insn (ILIST_INSN (p)); | |
497 | p = ILIST_NEXT (p); | |
498 | } | |
499 | } | |
500 | ||
501 | /* Dumps a list of boundaries pointed to by BNDS. */ | |
502 | void | |
503 | dump_blist (blist_t bnds) | |
504 | { | |
505 | for (; bnds; bnds = BLIST_NEXT (bnds)) | |
506 | { | |
507 | bnd_t bnd = BLIST_BND (bnds); | |
b8698a0f | 508 | |
e855c69d AB |
509 | sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd))); |
510 | dump_ilist (BND_PTR (bnd)); | |
511 | sel_print ("] "); | |
512 | } | |
513 | } | |
514 | ||
515 | /* Dumps a list of fences pointed to by L. */ | |
516 | void | |
517 | dump_flist (flist_t l) | |
518 | { | |
519 | while (l) | |
520 | { | |
521 | dump_insn_1 (FENCE_INSN (FLIST_FENCE (l)), dump_flist_insn_flags); | |
522 | sel_print (" "); | |
523 | l = FLIST_NEXT (l); | |
524 | } | |
525 | } | |
526 | ||
527 | /* Dumps an insn vector SUCCS. */ | |
528 | void | |
529 | dump_insn_vector (rtx_vec_t succs) | |
530 | { | |
3f207ab3 | 531 | for (rtx_insn *succ : succs) |
e855c69d AB |
532 | if (succ) |
533 | dump_insn (succ); | |
534 | else | |
535 | sel_print ("NULL "); | |
536 | } | |
537 | ||
538 | /* Dumps a hard reg set SET to FILE using PREFIX. */ | |
539 | static void | |
540 | print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set) | |
541 | { | |
542 | int i; | |
543 | ||
544 | fprintf (file, "%s{ ", prefix); | |
545 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
546 | { | |
547 | if (TEST_HARD_REG_BIT (set, i)) | |
548 | fprintf (file, "%d ", i); | |
549 | } | |
550 | fprintf (file, "}\n"); | |
551 | } | |
552 | ||
553 | /* Dumps a hard reg set SET using PREFIX. */ | |
554 | void | |
555 | dump_hard_reg_set (const char *prefix, HARD_REG_SET set) | |
556 | { | |
557 | print_hard_reg_set (sched_dump, prefix, set); | |
558 | } | |
559 | ||
560 | /* Pretty print INSN. This is used as a hook. */ | |
561 | const char * | |
ce1ce33a | 562 | sel_print_insn (const rtx_insn *insn, int aligned ATTRIBUTE_UNUSED) |
e855c69d AB |
563 | { |
564 | static char buf[80]; | |
565 | ||
b8698a0f | 566 | /* '+' before insn means it is a new cycle start and it's not been |
e855c69d | 567 | scheduled yet. '>' - has been scheduled. */ |
9771b263 | 568 | if (s_i_d.exists () && INSN_LUID (insn) > 0) |
e855c69d | 569 | if (GET_MODE (insn) == TImode) |
b8698a0f L |
570 | sprintf (buf, "%s %4d", |
571 | INSN_SCHED_TIMES (insn) > 0 ? "> " : "< ", | |
e855c69d AB |
572 | INSN_UID (insn)); |
573 | else | |
b8698a0f L |
574 | sprintf (buf, "%s %4d", |
575 | INSN_SCHED_TIMES (insn) > 0 ? "! " : " ", | |
e855c69d AB |
576 | INSN_UID (insn)); |
577 | else | |
578 | if (GET_MODE (insn) == TImode) | |
579 | sprintf (buf, "+ %4d", INSN_UID (insn)); | |
580 | else | |
581 | sprintf (buf, " %4d", INSN_UID (insn)); | |
582 | ||
583 | return buf; | |
584 | } | |
585 | \f | |
586 | ||
587 | /* Functions for pretty printing of CFG. */ | |
7eba871a | 588 | /* FIXME: Using pretty-print here could simplify this stuff. */ |
e855c69d AB |
589 | |
590 | /* Replace all occurencies of STR1 to STR2 in BUF. | |
591 | The BUF must be large enough to hold the result. */ | |
592 | static void | |
593 | replace_str_in_buf (char *buf, const char *str1, const char *str2) | |
594 | { | |
595 | int buf_len = strlen (buf); | |
596 | int str1_len = strlen (str1); | |
597 | int str2_len = strlen (str2); | |
598 | int diff = str2_len - str1_len; | |
599 | ||
600 | char *p = buf; | |
601 | do | |
602 | { | |
603 | p = strstr (p, str1); | |
b8698a0f | 604 | if (p) |
e855c69d AB |
605 | { |
606 | char *p1 = p + str1_len; | |
607 | /* Copy the rest of buf and '\0'. */ | |
608 | int n = buf + buf_len - p1; | |
609 | int i; | |
610 | ||
611 | /* Shift str by DIFF chars. */ | |
612 | if (diff > 0) | |
613 | for (i = n; i >= 0; i--) | |
614 | p1[i + diff] = p1[i]; | |
615 | else | |
616 | for (i = 0; i <= n; i++) | |
617 | p1[i + diff] = p1[i]; | |
618 | ||
619 | /* Copy str2. */ | |
620 | for (i = 0; i < str2_len; i++) | |
621 | p[i] = str2[i]; | |
b8698a0f | 622 | |
e855c69d AB |
623 | p += str2_len; |
624 | buf_len += diff; | |
625 | } | |
626 | ||
627 | } | |
628 | while (p); | |
629 | } | |
630 | ||
7eba871a SB |
631 | /* Replace characters in BUF that have special meaning in .dot file. |
632 | Similar to pp_write_text_as_dot_label_to_stream. */ | |
67477881 | 633 | static void |
e855c69d AB |
634 | sel_prepare_string_for_dot_label (char *buf) |
635 | { | |
636 | static char specials_from[7][2] = { "<", ">", "{", "|", "}", "\"", | |
637 | "\n" }; | |
b8698a0f | 638 | static char specials_to[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}", |
e855c69d AB |
639 | "\\\"", "\\l" }; |
640 | unsigned i; | |
641 | ||
642 | for (i = 0; i < 7; i++) | |
643 | replace_str_in_buf (buf, specials_from[i], specials_to[i]); | |
644 | } | |
645 | ||
67477881 JJ |
646 | /* This function acts like printf but dumps to the sched_dump file. */ |
647 | void | |
648 | sel_print (const char *fmt, ...) | |
649 | { | |
650 | va_list ap; | |
651 | va_start (ap, fmt); | |
652 | if (sched_dump_to_dot_p) | |
653 | { | |
654 | char *message; | |
655 | if (vasprintf (&message, fmt, ap) >= 0 && message != NULL) | |
656 | { | |
657 | message = (char *) xrealloc (message, 2 * strlen (message) + 1); | |
658 | sel_prepare_string_for_dot_label (message); | |
659 | fprintf (sched_dump, "%s", message); | |
660 | free (message); | |
661 | } | |
662 | } | |
663 | else | |
664 | vfprintf (sched_dump, fmt, ap); | |
665 | va_end (ap); | |
666 | } | |
667 | ||
e855c69d AB |
668 | /* Dump INSN with FLAGS. */ |
669 | static void | |
670 | sel_dump_cfg_insn (insn_t insn, int flags) | |
671 | { | |
672 | int insn_flags = DUMP_INSN_UID | DUMP_INSN_PATTERN; | |
673 | ||
9771b263 | 674 | if (sched_luids.exists () && INSN_LUID (insn) > 0) |
e855c69d AB |
675 | { |
676 | if (flags & SEL_DUMP_CFG_INSN_SEQNO) | |
677 | insn_flags |= DUMP_INSN_SEQNO | DUMP_INSN_SCHED_CYCLE | DUMP_INSN_EXPR; | |
678 | } | |
679 | ||
680 | dump_insn_1 (insn, insn_flags); | |
681 | } | |
682 | ||
683 | /* Dump E to the dot file F. */ | |
684 | static void | |
685 | sel_dump_cfg_edge (FILE *f, edge e) | |
686 | { | |
687 | int w; | |
688 | const char *color; | |
689 | ||
690 | if (e->flags & EDGE_FALLTHRU) | |
691 | { | |
692 | w = 10; | |
693 | color = ", color = red"; | |
694 | } | |
695 | else if (e->src->next_bb == e->dest) | |
696 | { | |
697 | w = 3; | |
698 | color = ", color = blue"; | |
699 | } | |
700 | else | |
701 | { | |
702 | w = 1; | |
703 | color = ""; | |
704 | } | |
705 | ||
706 | fprintf (f, "\tbb%d -> bb%d [weight = %d%s];\n", | |
707 | e->src->index, e->dest->index, w, color); | |
708 | } | |
709 | ||
710 | ||
711 | /* Return true if BB has a predesessor from current region. | |
712 | TODO: Either make this function to trace back through empty block | |
713 | or just remove those empty blocks. */ | |
714 | static bool | |
715 | has_preds_in_current_region_p (basic_block bb) | |
716 | { | |
717 | edge e; | |
718 | edge_iterator ei; | |
719 | ||
720 | gcc_assert (!in_current_region_p (bb)); | |
721 | ||
722 | FOR_EACH_EDGE (e, ei, bb->preds) | |
723 | if (in_current_region_p (e->src)) | |
724 | return true; | |
725 | ||
726 | return false; | |
727 | } | |
728 | ||
729 | /* Dump a cfg region to the dot file F honoring FLAGS. */ | |
730 | static void | |
731 | sel_dump_cfg_2 (FILE *f, int flags) | |
732 | { | |
733 | basic_block bb; | |
734 | ||
735 | sched_dump_to_dot_p = true; | |
736 | switch_dump (f); | |
737 | ||
738 | fprintf (f, "digraph G {\n" | |
739 | "\tratio = 2.25;\n" | |
740 | "\tnode [shape = record, fontsize = 9];\n"); | |
741 | ||
742 | if (flags & SEL_DUMP_CFG_FUNCTION_NAME) | |
743 | fprintf (f, "function [label = \"%s\"];\n", current_function_name ()); | |
744 | ||
11cd3bed | 745 | FOR_EACH_BB_FN (bb, cfun) |
e855c69d AB |
746 | { |
747 | insn_t insn = BB_HEAD (bb); | |
748 | insn_t next_tail = NEXT_INSN (BB_END (bb)); | |
749 | edge e; | |
750 | edge_iterator ei; | |
751 | bool in_region_p = ((flags & SEL_DUMP_CFG_CURRENT_REGION) | |
752 | && in_current_region_p (bb)); | |
753 | bool full_p = (!(flags & SEL_DUMP_CFG_CURRENT_REGION) | |
754 | || in_region_p); | |
755 | bool some_p = full_p || has_preds_in_current_region_p (bb); | |
756 | const char *color; | |
757 | const char *style; | |
758 | ||
759 | if (!some_p) | |
760 | continue; | |
761 | ||
762 | if ((flags & SEL_DUMP_CFG_CURRENT_REGION) | |
763 | && in_current_region_p (bb) | |
764 | && BLOCK_TO_BB (bb->index) == 0) | |
765 | color = "color = green, "; | |
766 | else | |
767 | color = ""; | |
768 | ||
769 | if ((flags & SEL_DUMP_CFG_FENCES) | |
770 | && in_region_p) | |
771 | { | |
772 | style = ""; | |
773 | ||
774 | if (!sel_bb_empty_p (bb)) | |
775 | { | |
776 | bool first_p = true; | |
777 | insn_t tail = BB_END (bb); | |
778 | insn_t cur_insn; | |
779 | ||
780 | cur_insn = bb_note (bb); | |
781 | ||
782 | do | |
783 | { | |
784 | fence_t fence; | |
785 | ||
786 | cur_insn = NEXT_INSN (cur_insn); | |
787 | fence = flist_lookup (fences, cur_insn); | |
788 | ||
789 | if (fence != NULL) | |
790 | { | |
791 | if (!FENCE_SCHEDULED_P (fence)) | |
792 | { | |
793 | if (first_p) | |
794 | color = "color = red, "; | |
795 | else | |
796 | color = "color = yellow, "; | |
797 | } | |
798 | else | |
799 | color = "color = blue, "; | |
800 | } | |
801 | ||
802 | first_p = false; | |
803 | } | |
804 | while (cur_insn != tail); | |
805 | } | |
806 | } | |
807 | else if (!full_p) | |
808 | style = "style = dashed, "; | |
809 | else | |
810 | style = ""; | |
811 | ||
812 | fprintf (f, "\tbb%d [%s%slabel = \"{Basic block %d", bb->index, | |
813 | style, color, bb->index); | |
814 | ||
815 | if ((flags & SEL_DUMP_CFG_BB_LOOP) | |
816 | && bb->loop_father != NULL) | |
817 | fprintf (f, ", loop %d", bb->loop_father->num); | |
818 | ||
819 | if (full_p | |
820 | && (flags & SEL_DUMP_CFG_BB_NOTES_LIST)) | |
821 | { | |
822 | insn_t notes = BB_NOTE_LIST (bb); | |
823 | ||
824 | if (notes != NULL_RTX) | |
825 | { | |
826 | fprintf (f, "|"); | |
827 | ||
828 | /* For simplicity, we dump notes from note_list in reversed order | |
829 | to that what they will appear in the code. */ | |
830 | while (notes != NULL_RTX) | |
831 | { | |
832 | sel_dump_cfg_insn (notes, flags); | |
833 | fprintf (f, "\\l"); | |
834 | ||
835 | notes = PREV_INSN (notes); | |
836 | } | |
837 | } | |
838 | } | |
839 | ||
840 | if (full_p | |
841 | && (flags & SEL_DUMP_CFG_AV_SET) | |
842 | && in_current_region_p (bb) | |
843 | && !sel_bb_empty_p (bb)) | |
844 | { | |
845 | fprintf (f, "|"); | |
846 | ||
847 | if (BB_AV_SET_VALID_P (bb)) | |
848 | dump_av_set (BB_AV_SET (bb)); | |
849 | else if (BB_AV_LEVEL (bb) == -1) | |
850 | fprintf (f, "AV_SET needs update"); | |
851 | } | |
852 | ||
853 | if ((flags & SEL_DUMP_CFG_LV_SET) | |
854 | && !sel_bb_empty_p (bb)) | |
855 | { | |
856 | fprintf (f, "|"); | |
857 | ||
858 | if (BB_LV_SET_VALID_P (bb)) | |
859 | dump_lv_set (BB_LV_SET (bb)); | |
860 | else | |
861 | fprintf (f, "LV_SET needs update"); | |
862 | } | |
863 | ||
864 | if (full_p | |
865 | && (flags & SEL_DUMP_CFG_BB_INSNS)) | |
866 | { | |
867 | fprintf (f, "|"); | |
868 | while (insn != next_tail) | |
869 | { | |
870 | sel_dump_cfg_insn (insn, flags); | |
871 | fprintf (f, "\\l"); | |
872 | ||
873 | insn = NEXT_INSN (insn); | |
874 | } | |
875 | } | |
876 | ||
877 | fprintf (f, "}\"];\n"); | |
878 | ||
879 | FOR_EACH_EDGE (e, ei, bb->succs) | |
880 | if (full_p || in_current_region_p (e->dest)) | |
881 | sel_dump_cfg_edge (f, e); | |
882 | } | |
883 | ||
884 | fprintf (f, "}"); | |
885 | ||
886 | restore_dump (); | |
887 | sched_dump_to_dot_p = false; | |
888 | } | |
889 | ||
b8698a0f | 890 | /* Dump a cfg region to the file specified by TAG honoring flags. |
e855c69d AB |
891 | The file is created by the function. */ |
892 | static void | |
893 | sel_dump_cfg_1 (const char *tag, int flags) | |
894 | { | |
895 | char *buf; | |
896 | int i; | |
897 | FILE *f; | |
898 | ||
899 | ++sel_dump_cfg_fileno; | |
900 | ||
901 | if (!sel_dump_cfg_p) | |
902 | return; | |
903 | ||
904 | i = 1 + snprintf (NULL, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root, | |
905 | sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag); | |
906 | buf = XNEWVEC (char, i); | |
907 | snprintf (buf, i, "%s/%s%05d-%s.dot", sel_debug_cfg_root, | |
908 | sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag); | |
909 | ||
910 | f = fopen (buf, "w"); | |
911 | ||
912 | if (f == NULL) | |
913 | fprintf (stderr, "Can't create file: %s.\n", buf); | |
914 | else | |
915 | { | |
916 | sel_dump_cfg_2 (f, flags); | |
917 | ||
918 | fclose (f); | |
919 | } | |
920 | ||
921 | free (buf); | |
922 | } | |
923 | ||
924 | /* Setup cfg dumping flags. Used for debugging. */ | |
925 | void | |
926 | setup_dump_cfg_params (void) | |
927 | { | |
928 | sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS; | |
929 | sel_dump_cfg_p = 0; | |
930 | sel_debug_cfg_root_postfix = sel_debug_cfg_root_postfix_default; | |
931 | } | |
932 | ||
933 | /* Debug a cfg region with FLAGS. */ | |
934 | void | |
935 | sel_debug_cfg_1 (int flags) | |
936 | { | |
937 | bool t1 = sel_dump_cfg_p; | |
938 | int t2 = sel_dump_cfg_fileno; | |
939 | ||
940 | sel_dump_cfg_p = true; | |
941 | sel_dump_cfg_fileno = ++sel_debug_cfg_fileno; | |
942 | ||
943 | sel_dump_cfg_1 ("sel-debug-cfg", flags); | |
944 | ||
945 | sel_dump_cfg_fileno = t2; | |
946 | sel_dump_cfg_p = t1; | |
947 | } | |
948 | \f | |
949 | /* Dumps av_set AV to stderr. */ | |
24e47c76 | 950 | DEBUG_FUNCTION void |
e855c69d AB |
951 | debug_av_set (av_set_t av) |
952 | { | |
953 | switch_dump (stderr); | |
954 | dump_av_set (av); | |
955 | sel_print ("\n"); | |
956 | restore_dump (); | |
957 | } | |
958 | ||
959 | /* Dump LV to stderr. */ | |
24e47c76 | 960 | DEBUG_FUNCTION void |
e855c69d AB |
961 | debug_lv_set (regset lv) |
962 | { | |
963 | switch_dump (stderr); | |
964 | dump_lv_set (lv); | |
965 | sel_print ("\n"); | |
966 | restore_dump (); | |
967 | } | |
968 | ||
969 | /* Dump an instruction list P to stderr. */ | |
24e47c76 | 970 | DEBUG_FUNCTION void |
e855c69d AB |
971 | debug_ilist (ilist_t p) |
972 | { | |
973 | switch_dump (stderr); | |
974 | dump_ilist (p); | |
975 | sel_print ("\n"); | |
976 | restore_dump (); | |
977 | } | |
978 | ||
979 | /* Dump a boundary list BNDS to stderr. */ | |
24e47c76 | 980 | DEBUG_FUNCTION void |
e855c69d AB |
981 | debug_blist (blist_t bnds) |
982 | { | |
983 | switch_dump (stderr); | |
984 | dump_blist (bnds); | |
985 | sel_print ("\n"); | |
986 | restore_dump (); | |
987 | } | |
988 | ||
e855c69d | 989 | /* Dump a hard reg set SET to stderr. */ |
24e47c76 | 990 | DEBUG_FUNCTION void |
e855c69d AB |
991 | debug_hard_reg_set (HARD_REG_SET set) |
992 | { | |
993 | switch_dump (stderr); | |
994 | dump_hard_reg_set ("", set); | |
995 | sel_print ("\n"); | |
996 | restore_dump (); | |
997 | } | |
998 | ||
999 | /* Debug a cfg region with default flags. */ | |
1000 | void | |
1001 | sel_debug_cfg (void) | |
1002 | { | |
1003 | sel_debug_cfg_1 (sel_debug_cfg_flags); | |
1004 | } | |
1005 | ||
1006 | /* Print a current cselib value for X's address to stderr. */ | |
24e47c76 | 1007 | DEBUG_FUNCTION rtx |
e855c69d AB |
1008 | debug_mem_addr_value (rtx x) |
1009 | { | |
1010 | rtx t, addr; | |
ef4bddc2 | 1011 | machine_mode address_mode; |
e855c69d AB |
1012 | |
1013 | gcc_assert (MEM_P (x)); | |
372d6395 | 1014 | address_mode = get_address_mode (x); |
d4ebfa65 | 1015 | |
e855c69d | 1016 | t = shallow_copy_rtx (x); |
4deef538 AO |
1017 | if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t))) |
1018 | XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t)); | |
e855c69d AB |
1019 | |
1020 | t = canon_rtx (t); | |
1021 | addr = get_addr (XEXP (t, 0)); | |
1022 | debug_rtx (t); | |
1023 | debug_rtx (addr); | |
1024 | return t; | |
1025 | } | |
dfb0e60d | 1026 | #endif |
e855c69d | 1027 |