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