xref: /openbsd/gnu/usr.bin/gcc/gcc/ra-debug.c (revision c87b03e5)
1 /* Graph coloring register allocator
2    Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3    Contributed by Michael Matz <matz@suse.de>
4    and Daniel Berlin <dan@cgsoftware.com>.
5 
6    This file is part of GCC.
7 
8    GCC is free software; you can redistribute it and/or modify it under the
9    terms of the GNU General Public License as published by the Free Software
10    Foundation; either version 2, or (at your option) any later version.
11 
12    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15    details.
16 
17    You should have received a copy of the GNU General Public License along
18    with GCC; see the file COPYING.  If not, write to the Free Software
19    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "rtl.h"
24 #include "insn-config.h"
25 #include "recog.h"
26 #include "function.h"
27 #include "hard-reg-set.h"
28 #include "basic-block.h"
29 #include "df.h"
30 #include "output.h"
31 #include "ra.h"
32 #include "tm_p.h"
33 
34 /* This file contains various dumping and debug functions for
35    the graph coloring register allocator.  */
36 
37 static void ra_print_rtx_1op PARAMS ((FILE *, rtx));
38 static void ra_print_rtx_2op PARAMS ((FILE *, rtx));
39 static void ra_print_rtx_3op PARAMS ((FILE *, rtx));
40 static void ra_print_rtx_object PARAMS ((FILE *, rtx));
41 
42 /* The hardregs as names, for debugging.  */
43 static const char *const reg_class_names[] = REG_CLASS_NAMES;
44 
45 /* Print a message to the dump file, if debug_new_regalloc and LEVEL
46    have any bits in common.  */
47 
48 void
ra_debug_msg(unsigned int level,const char * format,...)49 ra_debug_msg VPARAMS ((unsigned int level, const char *format, ...))
50 {
51   VA_OPEN (ap, format);
52   VA_FIXEDARG (ap, unsigned int, level);
53   VA_FIXEDARG (ap, const char *, format);
54   if ((debug_new_regalloc & level) != 0 && rtl_dump_file != NULL)
55     vfprintf (rtl_dump_file, format, ap);
56   VA_CLOSE (ap);
57 }
58 
59 
60 /* The following ra_print_xxx() functions print RTL expressions
61    in concise infix form.  If the mode can be seen from context it's
62    left out.  Most operators are represented by their graphical
63    characters, e.g. LE as "<=".  Unknown constructs are currently
64    printed with print_inline_rtx(), which disrupts the nice layout.
65    Currently only the inline asm things are written this way.  */
66 
67 /* Print rtx X, which is a one operand rtx (op:mode (Y)), as
68    "op(Y)" to FILE.  */
69 
70 static void
ra_print_rtx_1op(file,x)71 ra_print_rtx_1op (file, x)
72      FILE *file;
73      rtx x;
74 {
75   enum rtx_code code = GET_CODE (x);
76   rtx op0 = XEXP (x, 0);
77   switch (code)
78     {
79       case NEG:
80       case NOT:
81 	  fputs ((code == NEG) ? "-(" : "~(", file);
82 	  ra_print_rtx (file, op0, 0);
83 	  fputs (")", file);
84 	  break;
85       case HIGH:
86 	  fputs ("hi(", file);
87 	  ra_print_rtx (file, op0, 0);
88 	  fputs (")", file);
89 	  break;
90       default:
91 	  fprintf (file, "%s", GET_RTX_NAME (code));
92 	  if (GET_MODE (x) != VOIDmode)
93 	    fprintf (file, ":%s(", GET_MODE_NAME (GET_MODE (x)));
94 	  else
95 	    fputs ("(", file);
96 	  ra_print_rtx (file, op0, 0);
97 	  fputs (")", file);
98 	  break;
99     }
100 }
101 
102 /* Print rtx X, which is a two operand rtx (op:mode (Y) (Z))
103    as "(Y op Z)", if the operand is know, or as "op(Y, Z)", if not,
104    to FILE.  */
105 
106 static void
ra_print_rtx_2op(file,x)107 ra_print_rtx_2op (file, x)
108      FILE *file;
109      rtx x;
110 {
111   int infix = 1;
112   const char *opname = "shitop";
113   enum rtx_code code = GET_CODE (x);
114   rtx op0 = XEXP (x, 0);
115   rtx op1 = XEXP (x, 1);
116   switch (code)
117     {
118       /* class '2' */
119       case COMPARE: opname = "?"; break;
120       case MINUS: opname = "-"; break;
121       case DIV: opname = "/"; break;
122       case UDIV: opname = "u/"; break;
123       case MOD: opname = "%"; break;
124       case UMOD: opname = "u%"; break;
125       case ASHIFT: opname = "<<"; break;
126       case ASHIFTRT: opname = "a>>"; break;
127       case LSHIFTRT: opname = "l>>"; break;
128       /* class 'c' */
129       case PLUS: opname = "+"; break;
130       case MULT: opname = "*"; break;
131       case AND: opname = "&"; break;
132       case IOR: opname = "|"; break;
133       case XOR: opname = "^"; break;
134       /* class '<' */
135       case NE: opname = "!="; break;
136       case EQ: opname = "=="; break;
137       case GE: opname = "s>="; break;
138       case GT: opname = "s>"; break;
139       case LE: opname = "s<="; break;
140       case LT: opname = "s<"; break;
141       case GEU: opname = "u>="; break;
142       case GTU: opname = "u>"; break;
143       case LEU: opname = "u<="; break;
144       case LTU: opname = "u<"; break;
145       default:
146 		infix = 0;
147 		opname = GET_RTX_NAME (code);
148 		break;
149     }
150   if (infix)
151     {
152       fputs ("(", file);
153       ra_print_rtx (file, op0, 0);
154       fprintf (file, " %s ", opname);
155       ra_print_rtx (file, op1, 0);
156       fputs (")", file);
157     }
158   else
159     {
160       fprintf (file, "%s(", opname);
161       ra_print_rtx (file, op0, 0);
162       fputs (", ", file);
163       ra_print_rtx (file, op1, 0);
164       fputs (")", file);
165     }
166 }
167 
168 /* Print rtx X, which a three operand rtx to FILE.
169    I.e. X is either an IF_THEN_ELSE, or a bitmap operation.  */
170 
171 static void
ra_print_rtx_3op(file,x)172 ra_print_rtx_3op (file, x)
173      FILE *file;
174      rtx x;
175 {
176   enum rtx_code code = GET_CODE (x);
177   rtx op0 = XEXP (x, 0);
178   rtx op1 = XEXP (x, 1);
179   rtx op2 = XEXP (x, 2);
180   if (code == IF_THEN_ELSE)
181     {
182       ra_print_rtx (file, op0, 0);
183       fputs (" ? ", file);
184       ra_print_rtx (file, op1, 0);
185       fputs (" : ", file);
186       ra_print_rtx (file, op2, 0);
187     }
188   else
189     {
190       /* Bitmap-operation */
191       fprintf (file, "%s:%s(", GET_RTX_NAME (code),
192 	       GET_MODE_NAME (GET_MODE (x)));
193       ra_print_rtx (file, op0, 0);
194       fputs (", ", file);
195       ra_print_rtx (file, op1, 0);
196       fputs (", ", file);
197       ra_print_rtx (file, op2, 0);
198       fputs (")", file);
199     }
200 }
201 
202 /* Print rtx X, which represents an object (class 'o' or some constructs
203    of class 'x' (e.g. subreg)), to FILE.
204    (reg XX) rtl is represented as "pXX", of XX was a pseudo,
205    as "name" it name is the nonnull hardreg name, or as "hXX", if XX
206    is a hardreg, whose name is NULL, or empty.  */
207 
208 static void
ra_print_rtx_object(file,x)209 ra_print_rtx_object (file, x)
210      FILE *file;
211      rtx x;
212 {
213   enum rtx_code code = GET_CODE (x);
214   enum machine_mode mode = GET_MODE (x);
215   switch (code)
216     {
217       case CONST_INT:
218 	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, XWINT (x, 0));
219 	  break;
220       case CONST_DOUBLE:
221 	    {
222 	      int i, num = 0;
223 	      const char *fmt = GET_RTX_FORMAT (code);
224 	      fputs ("dbl(", file);
225 	      for (i = 0; i < GET_RTX_LENGTH (code); i++)
226 		{
227 		  if (num)
228 		    fputs (", ", file);
229 		  if (fmt[i] == 'e' && XEXP (x, i))
230 		    /* The MEM or other stuff */
231 		    {
232 		      ra_print_rtx (file, XEXP (x, i), 0);
233 		      num++;
234 		    }
235 		  else if (fmt[i] == 'w')
236 		    {
237 		      fprintf (file, HOST_WIDE_INT_PRINT_HEX, XWINT (x, i));
238 		      num++;
239 		    }
240 		}
241 	      break;
242 	    }
243       case CONST_STRING: fprintf (file, "\"%s\"", XSTR (x, 0)); break;
244       case CONST: fputs ("const(", file);
245 		  ra_print_rtx (file, XEXP (x, 0), 0);
246 		  fputs (")", file);
247 		  break;
248       case PC: fputs ("pc", file); break;
249       case REG:
250 	       {
251 		 int regno = REGNO (x);
252 		 if (regno < FIRST_PSEUDO_REGISTER)
253 		   {
254 		     int i, nregs = HARD_REGNO_NREGS (regno, mode);
255 		     if (nregs > 1)
256 		       fputs ("[", file);
257 		     for (i = 0; i < nregs; i++)
258 		       {
259 			 if (i)
260 			   fputs (", ", file);
261 			 if (reg_names[regno+i] && *reg_names[regno + i])
262 			   fprintf (file, "%s", reg_names[regno + i]);
263 			 else
264 			   fprintf (file, "h%d", regno + i);
265 		       }
266 		     if (nregs > 1)
267 		       fputs ("]", file);
268 		   }
269 		 else
270 		   fprintf (file, "p%d", regno);
271 		 break;
272 	       }
273       case SUBREG:
274 	       {
275 		 rtx sub = SUBREG_REG (x);
276 		 int ofs = SUBREG_BYTE (x);
277 		 if (GET_CODE (sub) == REG
278 		     && REGNO (sub) < FIRST_PSEUDO_REGISTER)
279 		   {
280 		     int regno = REGNO (sub);
281 		     int i, nregs = HARD_REGNO_NREGS (regno, mode);
282 		     regno += subreg_regno_offset (regno, GET_MODE (sub),
283 						   ofs, mode);
284 		     if (nregs > 1)
285 		       fputs ("[", file);
286 		     for (i = 0; i < nregs; i++)
287 		       {
288 			 if (i)
289 			   fputs (", ", file);
290 			 if (reg_names[regno+i])
291 			   fprintf (file, "%s", reg_names[regno + i]);
292 			 else
293 			   fprintf (file, "h%d", regno + i);
294 		       }
295 		     if (nregs > 1)
296 		       fputs ("]", file);
297 		   }
298 		 else
299 		   {
300 		     ra_print_rtx (file, sub, 0);
301 		     fprintf (file, ":[%s+%d]", GET_MODE_NAME (mode), ofs);
302 		   }
303 		 break;
304 	       }
305       case SCRATCH: fputs ("scratch", file); break;
306       case CONCAT: ra_print_rtx_2op (file, x); break;
307       case HIGH: ra_print_rtx_1op (file, x); break;
308       case LO_SUM:
309 		 fputs ("(", file);
310 		 ra_print_rtx (file, XEXP (x, 0), 0);
311 		 fputs (" + lo(", file);
312 		 ra_print_rtx (file, XEXP (x, 1), 0);
313 		 fputs ("))", file);
314 		 break;
315       case MEM: fputs ("[", file);
316 		ra_print_rtx (file, XEXP (x, 0), 0);
317 		fprintf (file, "]:%s", GET_MODE_NAME (GET_MODE (x)));
318 		/* XXX print alias set too ?? */
319 		break;
320       case LABEL_REF:
321 		  {
322 		    rtx sub = XEXP (x, 0);
323 		    if (GET_CODE (sub) == NOTE
324 			&& NOTE_LINE_NUMBER (sub) == NOTE_INSN_DELETED_LABEL)
325 		      fprintf (file, "(deleted uid=%d)", INSN_UID (sub));
326 		    else if (GET_CODE (sub) == CODE_LABEL)
327 		      fprintf (file, "L%d", CODE_LABEL_NUMBER (sub));
328 		    else
329 		      fprintf (file, "(nonlabel uid=%d)", INSN_UID (sub));
330 		  }
331 		break;
332       case SYMBOL_REF:
333 		fprintf (file, "sym(\"%s\")", XSTR (x, 0)); break;
334       case CC0: fputs ("cc0", file); break;
335       default: print_inline_rtx (file, x, 0); break;
336     }
337 }
338 
339 /* Print a general rtx X to FILE in nice infix form.
340    If WITH_PN is set, and X is one of the toplevel constructs
341    (insns, notes, labels or barriers), then print also the UIDs of
342    the preceding and following insn.  */
343 
344 void
ra_print_rtx(file,x,with_pn)345 ra_print_rtx (file, x, with_pn)
346      FILE *file;
347      rtx x;
348      int with_pn;
349 {
350   enum rtx_code code;
351   char class;
352   int unhandled = 0;
353   if (!x)
354     return;
355   code = GET_CODE (x);
356   class = GET_RTX_CLASS (code);
357 
358   /* First handle the insn like constructs.  */
359   if (INSN_P (x) || code == NOTE || code == CODE_LABEL || code == BARRIER)
360     {
361       if (INSN_P (x))
362 	fputs ("  ", file);
363       /* Non-insns are prefixed by a ';'.  */
364       if (code == BARRIER)
365 	fputs ("; ", file);
366       else if (code == NOTE)
367 	/* But notes are indented very far right.  */
368 	fprintf (file, "\t\t\t\t\t; ");
369       else if (code == CODE_LABEL)
370 	/* And labels have their Lxx name first, before the actual UID.  */
371 	{
372 	  fprintf (file, "L%d:\t; ", CODE_LABEL_NUMBER (x));
373 	  if (LABEL_NAME (x))
374 	    fprintf (file, "(%s) ", LABEL_NAME (x));
375 	  switch (LABEL_KIND (x))
376 	    {
377 	    case LABEL_NORMAL: break;
378 	    case LABEL_STATIC_ENTRY: fputs (" (entry)", file); break;
379 	    case LABEL_GLOBAL_ENTRY: fputs (" (global entry)", file); break;
380 	    case LABEL_WEAK_ENTRY: fputs (" (weak entry)", file); break;
381 	    default: abort();
382 	    }
383 	  fprintf (file, " [%d uses] uid=(", LABEL_NUSES (x));
384 	}
385       fprintf (file, "%d", INSN_UID (x));
386       if (with_pn)
387 	fprintf (file, " %d %d", PREV_INSN (x) ? INSN_UID (PREV_INSN (x)) : 0,
388 		 NEXT_INSN (x) ? INSN_UID (NEXT_INSN (x)) : 0);
389       if (code == BARRIER)
390 	fputs (" -------- barrier ---------", file);
391       else if (code == CODE_LABEL)
392 	fputs (")", file);
393       else if (code == NOTE)
394 	{
395 	  int ln = NOTE_LINE_NUMBER (x);
396 	  if (ln >= (int) NOTE_INSN_BIAS && ln < (int) NOTE_INSN_MAX)
397 	    fprintf (file, " %s", GET_NOTE_INSN_NAME (ln));
398 	  else
399 	    {
400 	      fprintf (file, " line %d", ln);
401 	      if (NOTE_SOURCE_FILE (x))
402 		fprintf (file, ":%s", NOTE_SOURCE_FILE (x));
403 	    }
404 	}
405       else
406 	{
407 	  fprintf (file, "\t");
408 	  ra_print_rtx (file, PATTERN (x), 0);
409 	}
410       return;
411     }
412   switch (code)
413     {
414       /* Top-level stuff.  */
415       case PARALLEL:
416 	    {
417 	      int j;
418 	      for (j = 0; j < XVECLEN (x, 0); j++)
419 		{
420 		  if (j)
421 		    fputs ("\t;; ", file);
422 		  ra_print_rtx (file, XVECEXP (x, 0, j), 0);
423 		}
424 	      break;
425 	    }
426       case UNSPEC: case UNSPEC_VOLATILE:
427 	    {
428 	      int j;
429 	      fprintf (file, "unspec%s(%d",
430 		       (code == UNSPEC) ? "" : "_vol", XINT (x, 1));
431 	      for (j = 0; j < XVECLEN (x, 0); j++)
432 		{
433 		  fputs (", ", file);
434 		  ra_print_rtx (file, XVECEXP (x, 0, j), 0);
435 		}
436 	      fputs (")", file);
437 	      break;
438 	    }
439       case SET:
440 	  if (GET_CODE (SET_DEST (x)) == PC)
441 	    {
442 	      if (GET_CODE (SET_SRC (x)) == IF_THEN_ELSE
443 		  && GET_CODE (XEXP (SET_SRC(x), 2)) == PC)
444 		{
445 		  fputs ("if ", file);
446 		  ra_print_rtx (file, XEXP (SET_SRC (x), 0), 0);
447 		  fputs (" jump ", file);
448 		  ra_print_rtx (file, XEXP (SET_SRC (x), 1), 0);
449 		}
450 	      else
451 		{
452 		  fputs ("jump ", file);
453 		  ra_print_rtx (file, SET_SRC (x), 0);
454 		}
455 	    }
456 	  else
457 	    {
458 	      ra_print_rtx (file, SET_DEST (x), 0);
459 	      fputs (" <= ", file);
460 	      ra_print_rtx (file, SET_SRC (x), 0);
461 	    }
462 	  break;
463       case USE:
464 	      fputs ("use <= ", file);
465 	      ra_print_rtx (file, XEXP (x, 0), 0);
466 	      break;
467       case CLOBBER:
468 	      ra_print_rtx (file, XEXP (x, 0), 0);
469 	      fputs (" <= clobber", file);
470 	      break;
471       case CALL:
472 	      fputs ("call ", file);
473 	      ra_print_rtx (file, XEXP (x, 0), 0); /* Address */
474 	      fputs (" numargs=", file);
475 	      ra_print_rtx (file, XEXP (x, 1), 0); /* Num arguments */
476 	      break;
477       case RETURN:
478 	      fputs ("return", file);
479 	      break;
480       case TRAP_IF:
481 	      fputs ("if (", file);
482 	      ra_print_rtx (file, XEXP (x, 0), 0);
483 	      fputs (") trap ", file);
484 	      ra_print_rtx (file, XEXP (x, 1), 0);
485 	      break;
486       case RESX:
487 	      fprintf (file, "resx from region %d", XINT (x, 0));
488 	      break;
489 
490       /* Different things of class 'x' */
491       case SUBREG: ra_print_rtx_object (file, x); break;
492       case STRICT_LOW_PART:
493 		   fputs ("low(", file);
494 		   ra_print_rtx (file, XEXP (x, 0), 0);
495 		   fputs (")", file);
496 		   break;
497       default:
498 	unhandled = 1;
499 	break;
500     }
501   if (!unhandled)
502     return;
503   if (class == '1')
504     ra_print_rtx_1op (file, x);
505   else if (class == '2' || class == 'c' || class == '<')
506     ra_print_rtx_2op (file, x);
507   else if (class == '3' || class == 'b')
508     ra_print_rtx_3op (file, x);
509   else if (class == 'o')
510     ra_print_rtx_object (file, x);
511   else
512     print_inline_rtx (file, x, 0);
513 }
514 
515 /* This only calls ra_print_rtx(), but emits a final newline.  */
516 
517 void
ra_print_rtx_top(file,x,with_pn)518 ra_print_rtx_top (file, x, with_pn)
519      FILE *file;
520      rtx x;
521      int with_pn;
522 {
523   ra_print_rtx (file, x, with_pn);
524   fprintf (file, "\n");
525 }
526 
527 /* Callable from gdb.  This prints rtx X onto stderr.  */
528 
529 void
ra_debug_rtx(x)530 ra_debug_rtx (x)
531      rtx x;
532 {
533   ra_print_rtx_top (stderr, x, 1);
534 }
535 
536 /* This prints the content of basic block with index BBI.
537    The first and last insn are emitted with UIDs of prev and next insns.  */
538 
539 void
ra_debug_bbi(bbi)540 ra_debug_bbi (bbi)
541      int bbi;
542 {
543   basic_block bb = BASIC_BLOCK (bbi);
544   rtx insn;
545   for (insn = bb->head; insn; insn = NEXT_INSN (insn))
546     {
547       ra_print_rtx_top (stderr, insn, (insn == bb->head || insn == bb->end));
548       fprintf (stderr, "\n");
549       if (insn == bb->end)
550 	break;
551     }
552 }
553 
554 /* Beginning from INSN, emit NUM insns (if NUM is non-negative)
555    or emit a window of NUM insns around INSN, to stderr.  */
556 
557 void
ra_debug_insns(insn,num)558 ra_debug_insns (insn, num)
559      rtx insn;
560      int num;
561 {
562   int i, count = (num == 0 ? 1 : num < 0 ? -num : num);
563   if (num < 0)
564     for (i = count / 2; i > 0 && PREV_INSN (insn); i--)
565       insn = PREV_INSN (insn);
566   for (i = count; i > 0 && insn; insn = NEXT_INSN (insn), i--)
567     {
568       if (GET_CODE (insn) == CODE_LABEL)
569 	fprintf (stderr, "\n");
570       ra_print_rtx_top (stderr, insn, (i == count || i == 1));
571     }
572 }
573 
574 /* Beginning with INSN, emit the whole insn chain into FILE.
575    This also outputs comments when basic blocks start or end and omits
576    some notes, if flag_ra_dump_notes is zero.  */
577 
578 void
ra_print_rtl_with_bb(file,insn)579 ra_print_rtl_with_bb (file, insn)
580      FILE *file;
581      rtx insn;
582 {
583   basic_block last_bb, bb;
584   unsigned int num = 0;
585   if (!insn)
586     fputs ("nil", file);
587   last_bb = NULL;
588   for (; insn; insn = NEXT_INSN (insn))
589     {
590       if (GET_CODE (insn) == BARRIER)
591 	bb = NULL;
592       else
593 	bb = BLOCK_FOR_INSN (insn);
594       if (bb != last_bb)
595 	{
596 	  if (last_bb)
597 	    fprintf (file, ";; End of basic block %d\n", last_bb->index);
598 	  if (bb)
599 	    fprintf (file, ";; Begin of basic block %d\n", bb->index);
600 	  last_bb = bb;
601 	}
602       if (GET_CODE (insn) == CODE_LABEL)
603 	fputc ('\n', file);
604       if (GET_CODE (insn) == NOTE)
605 	{
606 	  /* Ignore basic block and maybe other notes not referencing
607 	     deleted things.  */
608 	  if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
609 	      && (flag_ra_dump_notes
610 		  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED
611 		  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))
612 	    {
613 	      ra_print_rtx_top (file, insn, (num == 0 || !NEXT_INSN (insn)));
614 	      num++;
615 	    }
616 	}
617       else
618 	{
619 	  ra_print_rtx_top (file, insn, (num == 0 || !NEXT_INSN (insn)));
620 	  num++;
621 	}
622     }
623 }
624 
625 /* Count how many insns were seen how often, while building the interference
626    graph, and prints the findings.  */
627 
628 void
dump_number_seen()629 dump_number_seen ()
630 {
631 #define N 17
632   int num[N];
633   int i;
634 
635   for (i = 0; i < N; i++)
636     num[i] = 0;
637   for (i = 0; i < get_max_uid (); i++)
638     if (number_seen[i] < N - 1)
639       num[number_seen[i]]++;
640     else
641       num[N - 1]++;
642   for (i = 0; i < N - 1; i++)
643     if (num[i])
644       ra_debug_msg (DUMP_PROCESS, "%d insns seen %d times\n", num[i], i);
645   if (num[N - 1])
646     ra_debug_msg (DUMP_PROCESS, "%d insns seen %d and more times\n", num[i],
647 	       N - 1);
648   ra_debug_msg (DUMP_PROCESS, "from overall %d insns\n", get_max_uid ());
649 #undef N
650 }
651 
652 /* Dump the interference graph, the move list and the webs.  */
653 
654 void
dump_igraph(df)655 dump_igraph (df)
656      struct df *df ATTRIBUTE_UNUSED;
657 {
658   struct move_list *ml;
659   unsigned int def1, def2;
660   int num = 0;
661   int num2;
662   unsigned int i;
663   if (!rtl_dump_file || (debug_new_regalloc & (DUMP_IGRAPH | DUMP_WEBS)) == 0)
664     return;
665   ra_debug_msg (DUMP_IGRAPH, "conflicts:\n  ");
666   for (def1 = 0; def1 < num_webs; def1++)
667     {
668       int num1 = num;
669       for (num2=0, def2 = 0; def2 < num_webs; def2++)
670         if (def1 != def2 && TEST_BIT (igraph, igraph_index (def1, def2)))
671 	  {
672 	    if (num1 == num)
673 	      {
674 	        if (SUBWEB_P (ID2WEB (def1)))
675 		  ra_debug_msg (DUMP_IGRAPH, "%d (SUBREG %d, %d) with ", def1,
676 			     ID2WEB (def1)->regno,
677 			     SUBREG_BYTE (ID2WEB (def1)->orig_x));
678 	        else
679 	          ra_debug_msg (DUMP_IGRAPH, "%d (REG %d) with ", def1,
680 			     ID2WEB (def1)->regno);
681 	      }
682 	    if ((num2 % 9) == 8)
683 	      ra_debug_msg (DUMP_IGRAPH, "\n              ");
684 	    num++;
685 	    num2++;
686 	    if (SUBWEB_P (ID2WEB (def2)))
687 	      ra_debug_msg (DUMP_IGRAPH, "%d(%d,%d) ", def2, ID2WEB (def2)->regno,
688 			 SUBREG_BYTE (ID2WEB (def2)->orig_x));
689 	    else
690 	      ra_debug_msg (DUMP_IGRAPH, "%d(%d) ", def2, ID2WEB (def2)->regno);
691 	  }
692       if (num1 != num)
693 	ra_debug_msg (DUMP_IGRAPH, "\n  ");
694     }
695   ra_debug_msg (DUMP_IGRAPH, "\n");
696   for (ml = wl_moves; ml; ml = ml->next)
697     if (ml->move)
698       {
699         ra_debug_msg (DUMP_IGRAPH, "move: insn %d: Web %d <-- Web %d\n",
700 	         INSN_UID (ml->move->insn), ml->move->target_web->id,
701 	         ml->move->source_web->id);
702       }
703   ra_debug_msg (DUMP_WEBS, "\nWebs:\n");
704   for (i = 0; i < num_webs; i++)
705     {
706       struct web *web = ID2WEB (i);
707 
708       ra_debug_msg (DUMP_WEBS, "  %4d : regno %3d", i, web->regno);
709       if (SUBWEB_P (web))
710 	{
711 	  ra_debug_msg (DUMP_WEBS, " sub %d", SUBREG_BYTE (web->orig_x));
712 	  ra_debug_msg (DUMP_WEBS, " par %d", find_web_for_subweb (web)->id);
713 	}
714       ra_debug_msg (DUMP_WEBS, " +%d (span %d, cost ",
715 		    web->add_hardregs, web->span_deaths);
716       ra_debug_msg (DUMP_WEBS, HOST_WIDE_INT_PRINT_DEC, web->spill_cost);
717       ra_debug_msg (DUMP_WEBS, ") (%s)", reg_class_names[web->regclass]);
718       if (web->spill_temp == 1)
719 	ra_debug_msg (DUMP_WEBS, " (spilltemp)");
720       else if (web->spill_temp == 2)
721 	ra_debug_msg (DUMP_WEBS, " (spilltem2)");
722       else if (web->spill_temp == 3)
723 	ra_debug_msg (DUMP_WEBS, " (short)");
724       if (web->type == PRECOLORED)
725         ra_debug_msg (DUMP_WEBS, " (precolored, color=%d)", web->color);
726       else if (find_web_for_subweb (web)->num_uses == 0)
727 	ra_debug_msg (DUMP_WEBS, " dead");
728       if (web->crosses_call)
729 	ra_debug_msg (DUMP_WEBS, " xcall");
730       if (web->regno >= max_normal_pseudo)
731 	ra_debug_msg (DUMP_WEBS, " stack");
732       ra_debug_msg (DUMP_WEBS, "\n");
733     }
734 }
735 
736 /* Dump the interference graph and webs in a format easily
737    parsable by programs.  Used to emit real world interference graph
738    to my custom graph colorizer.  */
739 
740 void
dump_igraph_machine()741 dump_igraph_machine ()
742 {
743   unsigned int i;
744 
745   if (!rtl_dump_file || (debug_new_regalloc & DUMP_IGRAPH_M) == 0)
746     return;
747   ra_debug_msg (DUMP_IGRAPH_M, "g %d %d\n", num_webs - num_subwebs,
748 	     FIRST_PSEUDO_REGISTER);
749   for (i = 0; i < num_webs - num_subwebs; i++)
750     {
751       struct web *web = ID2WEB (i);
752       struct conflict_link *cl;
753       int flags = 0;
754       int numc = 0;
755       int col = 0;
756       flags = web->spill_temp & 0xF;
757       flags |= ((web->type == PRECOLORED) ? 1 : 0) << 4;
758       flags |= (web->add_hardregs & 0xF) << 5;
759       for (cl = web->conflict_list; cl; cl = cl->next)
760 	if (cl->t->id < web->id)
761 	  numc++;
762       ra_debug_msg (DUMP_IGRAPH_M, "n %d %d %d %d %d %d %d\n",
763 		 web->id, web->color, flags,
764 		 (unsigned int)web->spill_cost, web->num_defs, web->num_uses,
765 		 numc);
766       if (web->type != PRECOLORED)
767 	{
768 	  ra_debug_msg (DUMP_IGRAPH_M, "s %d", web->id);
769 	  while (1)
770 	    {
771 	      unsigned int u = 0;
772 	      int n;
773 	      for (n = 0; n < 32 && col < FIRST_PSEUDO_REGISTER; n++, col++)
774 		if (TEST_HARD_REG_BIT (web->usable_regs, col))
775 		  u |= 1 << n;
776 	      ra_debug_msg (DUMP_IGRAPH_M, " %u", u);
777 	      if (col >= FIRST_PSEUDO_REGISTER)
778 		break;
779 	    }
780 	  ra_debug_msg (DUMP_IGRAPH_M, "\n");
781 	}
782       if (numc)
783 	{
784 	  ra_debug_msg (DUMP_IGRAPH_M, "c %d", web->id);
785 	  for (cl = web->conflict_list; cl; cl = cl->next)
786 	    {
787 	      if (cl->t->id < web->id)
788 		ra_debug_msg (DUMP_IGRAPH_M, " %d", cl->t->id);
789 	    }
790 	  ra_debug_msg (DUMP_IGRAPH_M, "\n");
791 	}
792     }
793   ra_debug_msg (DUMP_IGRAPH_M, "e\n");
794 }
795 
796 /* This runs after colorization and changing the insn stream.
797    It temporarily replaces all pseudo registers with their colors,
798    and emits information, if the resulting insns are strictly valid.  */
799 
800 void
dump_constraints()801 dump_constraints ()
802 {
803   rtx insn;
804   int i;
805   if (!rtl_dump_file || (debug_new_regalloc & DUMP_CONSTRAINTS) == 0)
806     return;
807   for (i = FIRST_PSEUDO_REGISTER; i < ra_max_regno; i++)
808     if (regno_reg_rtx[i] && GET_CODE (regno_reg_rtx[i]) == REG)
809       REGNO (regno_reg_rtx[i])
810 	  = ra_reg_renumber[i] >= 0 ? ra_reg_renumber[i] : i;
811   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
812     if (INSN_P (insn))
813       {
814 	int code;
815 	int uid = INSN_UID (insn);
816 	int o;
817 	/* Don't simply force rerecognition, as combine might left us
818 	   with some unrecongnizable ones, which later leads to aborts
819 	   in regclass, if we now destroy the remembered INSN_CODE().  */
820 	/*INSN_CODE (insn) = -1;*/
821 	code = recog_memoized (insn);
822 	if (code < 0)
823 	  {
824 	    ra_debug_msg (DUMP_CONSTRAINTS,
825 		       "%d: asm insn or not recognizable.\n", uid);
826 	    continue;
827 	  }
828 	ra_debug_msg (DUMP_CONSTRAINTS,
829 		   "%d: code %d {%s}, %d operands, constraints: ",
830 		   uid, code, insn_data[code].name, recog_data.n_operands);
831         extract_insn (insn);
832 	/*preprocess_constraints ();*/
833 	for (o = 0; o < recog_data.n_operands; o++)
834 	  {
835 	    ra_debug_msg (DUMP_CONSTRAINTS,
836 		       "%d:%s ", o, recog_data.constraints[o]);
837 	  }
838 	if (constrain_operands (1))
839 	  ra_debug_msg (DUMP_CONSTRAINTS, "matches strictly alternative %d",
840 		     which_alternative);
841 	else
842 	  ra_debug_msg (DUMP_CONSTRAINTS, "doesn't match strictly");
843 	ra_debug_msg (DUMP_CONSTRAINTS, "\n");
844       }
845   for (i = FIRST_PSEUDO_REGISTER; i < ra_max_regno; i++)
846     if (regno_reg_rtx[i] && GET_CODE (regno_reg_rtx[i]) == REG)
847       REGNO (regno_reg_rtx[i]) = i;
848 }
849 
850 /* This counts and emits the cumulated cost of all spilled webs,
851    preceded by a custom message MSG, with debug level LEVEL.  */
852 
853 void
dump_graph_cost(level,msg)854 dump_graph_cost (level, msg)
855      unsigned int level;
856      const char *msg;
857 {
858   unsigned int i;
859   unsigned HOST_WIDE_INT cost;
860   if (!rtl_dump_file || (debug_new_regalloc & level) == 0)
861     return;
862 
863   cost = 0;
864   for (i = 0; i < num_webs; i++)
865     {
866       struct web *web = id2web[i];
867       if (alias (web)->type == SPILLED)
868 	cost += web->orig_spill_cost;
869     }
870   ra_debug_msg (level, " spill cost of graph (%s) = ", msg ? msg : "");
871   ra_debug_msg (level, HOST_WIDE_INT_PRINT_UNSIGNED, cost);
872   ra_debug_msg (level, "\n");
873 }
874 
875 /* Dump the color assignment per web, the coalesced and spilled webs.  */
876 
877 void
dump_ra(df)878 dump_ra (df)
879      struct df *df ATTRIBUTE_UNUSED;
880 {
881   struct web *web;
882   struct dlist *d;
883   if (!rtl_dump_file || (debug_new_regalloc & DUMP_RESULTS) == 0)
884     return;
885 
886   ra_debug_msg (DUMP_RESULTS, "\nColored:\n");
887   for (d = WEBS(COLORED); d; d = d->next)
888     {
889       web = DLIST_WEB (d);
890       ra_debug_msg (DUMP_RESULTS, "  %4d : color %d\n", web->id, web->color);
891     }
892   ra_debug_msg (DUMP_RESULTS, "\nCoalesced:\n");
893   for (d = WEBS(COALESCED); d; d = d->next)
894     {
895       web = DLIST_WEB (d);
896       ra_debug_msg (DUMP_RESULTS, "  %4d : to web %d, color %d\n", web->id,
897 	         alias (web)->id, web->color);
898     }
899   ra_debug_msg (DUMP_RESULTS, "\nSpilled:\n");
900   for (d = WEBS(SPILLED); d; d = d->next)
901     {
902       web = DLIST_WEB (d);
903       ra_debug_msg (DUMP_RESULTS, "  %4d\n", web->id);
904     }
905   ra_debug_msg (DUMP_RESULTS, "\n");
906   dump_cost (DUMP_RESULTS);
907 }
908 
909 /* Calculate and dump the cumulated costs of certain types of insns
910    (loads, stores and copies).  */
911 
912 void
dump_static_insn_cost(file,message,prefix)913 dump_static_insn_cost (file, message, prefix)
914      FILE *file;
915      const char *message;
916      const char *prefix;
917 {
918   struct cost
919     {
920       unsigned HOST_WIDE_INT cost;
921       unsigned int count;
922     };
923   basic_block bb;
924   struct cost load, store, regcopy, selfcopy, overall;
925   memset (&load, 0, sizeof(load));
926   memset (&store, 0, sizeof(store));
927   memset (&regcopy, 0, sizeof(regcopy));
928   memset (&selfcopy, 0, sizeof(selfcopy));
929   memset (&overall, 0, sizeof(overall));
930 
931   if (!file)
932     return;
933 
934   FOR_EACH_BB (bb)
935     {
936       unsigned HOST_WIDE_INT block_cost = bb->frequency;
937       rtx insn, set;
938       for (insn = bb->head; insn; insn = NEXT_INSN (insn))
939 	{
940 	  /* Yes, yes.  We don't calculate the costs precisely.
941 	     Only for "simple enough" insns.  Those containing single
942 	     sets only.  */
943 	  if (INSN_P (insn) && ((set = single_set (insn)) != NULL))
944 	    {
945 	      rtx src = SET_SRC (set);
946 	      rtx dest = SET_DEST (set);
947 	      struct cost *pcost = NULL;
948 	      overall.cost += block_cost;
949 	      overall.count++;
950 	      if (rtx_equal_p (src, dest))
951 		pcost = &selfcopy;
952 	      else if (GET_CODE (src) == GET_CODE (dest)
953 		       && ((GET_CODE (src) == REG)
954 			   || (GET_CODE (src) == SUBREG
955 			       && GET_CODE (SUBREG_REG (src)) == REG
956 			       && GET_CODE (SUBREG_REG (dest)) == REG)))
957 		pcost = &regcopy;
958 	      else
959 		{
960 		  if (GET_CODE (src) == SUBREG)
961 		    src = SUBREG_REG (src);
962 		  if (GET_CODE (dest) == SUBREG)
963 		    dest = SUBREG_REG (dest);
964 		  if (GET_CODE (src) == MEM && GET_CODE (dest) != MEM
965 		      && memref_is_stack_slot (src))
966 		    pcost = &load;
967 		  else if (GET_CODE (src) != MEM && GET_CODE (dest) == MEM
968 			   && memref_is_stack_slot (dest))
969 		    pcost = &store;
970 		}
971 	      if (pcost)
972 		{
973 		  pcost->cost += block_cost;
974 		  pcost->count++;
975 		}
976 	    }
977 	  if (insn == bb->end)
978 	    break;
979 	}
980     }
981 
982   if (!prefix)
983     prefix = "";
984   fprintf (file, "static insn cost %s\n", message ? message : "");
985   fprintf (file, "  %soverall:\tnum=%6d\tcost=", prefix, overall.count);
986   fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, overall.cost);
987   fprintf (file, "\n");
988   fprintf (file, "  %sloads:\tnum=%6d\tcost=", prefix, load.count);
989   fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, load.cost);
990   fprintf (file, "\n");
991   fprintf (file, "  %sstores:\tnum=%6d\tcost=", prefix, store.count);
992   fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, store.cost);
993   fprintf (file, "\n");
994   fprintf (file, "  %sregcopy:\tnum=%6d\tcost=", prefix, regcopy.count);
995   fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, regcopy.cost);
996   fprintf (file, "\n");
997   fprintf (file, "  %sselfcpy:\tnum=%6d\tcost=", prefix, selfcopy.count);
998   fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, selfcopy.cost);
999   fprintf (file, "\n");
1000 }
1001 
1002 /* Returns nonzero, if WEB1 and WEB2 have some possible
1003    hardregs in common.  */
1004 
1005 int
web_conflicts_p(web1,web2)1006 web_conflicts_p (web1, web2)
1007      struct web *web1;
1008      struct web *web2;
1009 {
1010   if (web1->type == PRECOLORED && web2->type == PRECOLORED)
1011     return 0;
1012 
1013   if (web1->type == PRECOLORED)
1014     return TEST_HARD_REG_BIT (web2->usable_regs, web1->regno);
1015 
1016   if (web2->type == PRECOLORED)
1017     return TEST_HARD_REG_BIT (web1->usable_regs, web2->regno);
1018 
1019   return hard_regs_intersect_p (&web1->usable_regs, &web2->usable_regs);
1020 }
1021 
1022 /* Dump all uids of insns in which WEB is mentioned.  */
1023 
1024 void
dump_web_insns(web)1025 dump_web_insns (web)
1026      struct web *web;
1027 {
1028   unsigned int i;
1029 
1030   ra_debug_msg (DUMP_EVER, "Web: %i(%i)+%i class: %s freedom: %i degree %i\n",
1031 	     web->id, web->regno, web->add_hardregs,
1032 	     reg_class_names[web->regclass],
1033 	     web->num_freedom, web->num_conflicts);
1034   ra_debug_msg (DUMP_EVER, "   def insns:");
1035 
1036   for (i = 0; i < web->num_defs; ++i)
1037     {
1038       ra_debug_msg (DUMP_EVER, " %d ", INSN_UID (web->defs[i]->insn));
1039     }
1040 
1041   ra_debug_msg (DUMP_EVER, "\n   use insns:");
1042   for (i = 0; i < web->num_uses; ++i)
1043     {
1044       ra_debug_msg (DUMP_EVER, " %d ", INSN_UID (web->uses[i]->insn));
1045     }
1046   ra_debug_msg (DUMP_EVER, "\n");
1047 }
1048 
1049 /* Dump conflicts for web WEB.  */
1050 
1051 void
dump_web_conflicts(web)1052 dump_web_conflicts (web)
1053      struct web *web;
1054 {
1055   int num = 0;
1056   unsigned int def2;
1057 
1058   ra_debug_msg (DUMP_EVER, "Web: %i(%i)+%i class: %s freedom: %i degree %i\n",
1059 	     web->id, web->regno, web->add_hardregs,
1060 	     reg_class_names[web->regclass],
1061 	     web->num_freedom, web->num_conflicts);
1062 
1063   for (def2 = 0; def2 < num_webs; def2++)
1064     if (TEST_BIT (igraph, igraph_index (web->id, def2)) && web->id != def2)
1065       {
1066 	if ((num % 9) == 5)
1067 	  ra_debug_msg (DUMP_EVER, "\n             ");
1068 	num++;
1069 
1070 	ra_debug_msg (DUMP_EVER, " %d(%d)", def2, id2web[def2]->regno);
1071 	if (id2web[def2]->add_hardregs)
1072 	  ra_debug_msg (DUMP_EVER, "+%d", id2web[def2]->add_hardregs);
1073 
1074 	if (web_conflicts_p (web, id2web[def2]))
1075 	  ra_debug_msg (DUMP_EVER, "/x");
1076 
1077 	if (id2web[def2]->type == SELECT)
1078 	  ra_debug_msg (DUMP_EVER, "/s");
1079 
1080 	if (id2web[def2]->type == COALESCED)
1081 	  ra_debug_msg (DUMP_EVER,"/c/%d", alias (id2web[def2])->id);
1082       }
1083   ra_debug_msg (DUMP_EVER, "\n");
1084   {
1085     struct conflict_link *wl;
1086     num = 0;
1087     ra_debug_msg (DUMP_EVER, "By conflicts:     ");
1088     for (wl = web->conflict_list; wl; wl = wl->next)
1089       {
1090 	struct web* w = wl->t;
1091 	if ((num % 9) == 8)
1092 	  ra_debug_msg (DUMP_EVER, "\n              ");
1093 	num++;
1094 	ra_debug_msg (DUMP_EVER, "%d(%d)%s ", w->id, w->regno,
1095 		   web_conflicts_p (web, w) ? "+" : "");
1096       }
1097     ra_debug_msg (DUMP_EVER, "\n");
1098   }
1099 }
1100 
1101 /* Output HARD_REG_SET to stderr.  */
1102 
1103 void
debug_hard_reg_set(set)1104 debug_hard_reg_set (set)
1105      HARD_REG_SET set;
1106 {
1107   int i;
1108   for (i=0; i < FIRST_PSEUDO_REGISTER; ++i)
1109     {
1110       if (TEST_HARD_REG_BIT (set, i))
1111 	{
1112 	  fprintf (stderr, "%s ", reg_names[i]);
1113 	}
1114     }
1115   fprintf (stderr, "\n");
1116 }
1117 
1118 /*
1119 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
1120 */
1121