diff options
author | kan <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
commit | b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180 (patch) | |
tree | f6b0610f4a17fd26aa234354f050080f789861a4 /contrib/gcc/ra-debug.c | |
parent | 52e69d78eee5612ac195e0701a5cebe40d1ab0e1 (diff) | |
download | FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.zip FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.tar.gz |
Gcc 3.3.1-pre as of 2003-07-11.
Diffstat (limited to 'contrib/gcc/ra-debug.c')
-rw-r--r-- | contrib/gcc/ra-debug.c | 1120 |
1 files changed, 1120 insertions, 0 deletions
diff --git a/contrib/gcc/ra-debug.c b/contrib/gcc/ra-debug.c new file mode 100644 index 0000000..8daa63d --- /dev/null +++ b/contrib/gcc/ra-debug.c @@ -0,0 +1,1120 @@ +/* Graph coloring register allocator + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Contributed by Michael Matz <matz@suse.de> + and Daniel Berlin <dan@cgsoftware.com>. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with GCC; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "insn-config.h" +#include "recog.h" +#include "function.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "df.h" +#include "output.h" +#include "ra.h" +#include "tm_p.h" + +/* This file contains various dumping and debug functions for + the graph coloring register allocator. */ + +static void ra_print_rtx_1op PARAMS ((FILE *, rtx)); +static void ra_print_rtx_2op PARAMS ((FILE *, rtx)); +static void ra_print_rtx_3op PARAMS ((FILE *, rtx)); +static void ra_print_rtx_object PARAMS ((FILE *, rtx)); + +/* The hardregs as names, for debugging. */ +static const char *const reg_class_names[] = REG_CLASS_NAMES; + +/* Print a message to the dump file, if debug_new_regalloc and LEVEL + have any bits in common. */ + +void +ra_debug_msg VPARAMS ((unsigned int level, const char *format, ...)) +{ + VA_OPEN (ap, format); + VA_FIXEDARG (ap, unsigned int, level); + VA_FIXEDARG (ap, const char *, format); + if ((debug_new_regalloc & level) != 0 && rtl_dump_file != NULL) + vfprintf (rtl_dump_file, format, ap); + VA_CLOSE (ap); +} + + +/* The following ra_print_xxx() functions print RTL expressions + in concise infix form. If the mode can be seen from context it's + left out. Most operators are represented by their graphical + characters, e.g. LE as "<=". Unknown constructs are currently + printed with print_inline_rtx(), which disrupts the nice layout. + Currently only the inline asm things are written this way. */ + +/* Print rtx X, which is a one operand rtx (op:mode (Y)), as + "op(Y)" to FILE. */ + +static void +ra_print_rtx_1op (file, x) + FILE *file; + rtx x; +{ + enum rtx_code code = GET_CODE (x); + rtx op0 = XEXP (x, 0); + switch (code) + { + case NEG: + case NOT: + fputs ((code == NEG) ? "-(" : "~(", file); + ra_print_rtx (file, op0, 0); + fputs (")", file); + break; + case HIGH: + fputs ("hi(", file); + ra_print_rtx (file, op0, 0); + fputs (")", file); + break; + default: + fprintf (file, "%s", GET_RTX_NAME (code)); + if (GET_MODE (x) != VOIDmode) + fprintf (file, ":%s(", GET_MODE_NAME (GET_MODE (x))); + else + fputs ("(", file); + ra_print_rtx (file, op0, 0); + fputs (")", file); + break; + } +} + +/* Print rtx X, which is a two operand rtx (op:mode (Y) (Z)) + as "(Y op Z)", if the operand is know, or as "op(Y, Z)", if not, + to FILE. */ + +static void +ra_print_rtx_2op (file, x) + FILE *file; + rtx x; +{ + int infix = 1; + const char *opname = "shitop"; + enum rtx_code code = GET_CODE (x); + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + switch (code) + { + /* class '2' */ + case COMPARE: opname = "?"; break; + case MINUS: opname = "-"; break; + case DIV: opname = "/"; break; + case UDIV: opname = "u/"; break; + case MOD: opname = "%"; break; + case UMOD: opname = "u%"; break; + case ASHIFT: opname = "<<"; break; + case ASHIFTRT: opname = "a>>"; break; + case LSHIFTRT: opname = "l>>"; break; + /* class 'c' */ + case PLUS: opname = "+"; break; + case MULT: opname = "*"; break; + case AND: opname = "&"; break; + case IOR: opname = "|"; break; + case XOR: opname = "^"; break; + /* class '<' */ + case NE: opname = "!="; break; + case EQ: opname = "=="; break; + case GE: opname = "s>="; break; + case GT: opname = "s>"; break; + case LE: opname = "s<="; break; + case LT: opname = "s<"; break; + case GEU: opname = "u>="; break; + case GTU: opname = "u>"; break; + case LEU: opname = "u<="; break; + case LTU: opname = "u<"; break; + default: + infix = 0; + opname = GET_RTX_NAME (code); + break; + } + if (infix) + { + fputs ("(", file); + ra_print_rtx (file, op0, 0); + fprintf (file, " %s ", opname); + ra_print_rtx (file, op1, 0); + fputs (")", file); + } + else + { + fprintf (file, "%s(", opname); + ra_print_rtx (file, op0, 0); + fputs (", ", file); + ra_print_rtx (file, op1, 0); + fputs (")", file); + } +} + +/* Print rtx X, which a three operand rtx to FILE. + I.e. X is either an IF_THEN_ELSE, or a bitmap operation. */ + +static void +ra_print_rtx_3op (file, x) + FILE *file; + rtx x; +{ + enum rtx_code code = GET_CODE (x); + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + rtx op2 = XEXP (x, 2); + if (code == IF_THEN_ELSE) + { + ra_print_rtx (file, op0, 0); + fputs (" ? ", file); + ra_print_rtx (file, op1, 0); + fputs (" : ", file); + ra_print_rtx (file, op2, 0); + } + else + { + /* Bitmap-operation */ + fprintf (file, "%s:%s(", GET_RTX_NAME (code), + GET_MODE_NAME (GET_MODE (x))); + ra_print_rtx (file, op0, 0); + fputs (", ", file); + ra_print_rtx (file, op1, 0); + fputs (", ", file); + ra_print_rtx (file, op2, 0); + fputs (")", file); + } +} + +/* Print rtx X, which represents an object (class 'o' or some constructs + of class 'x' (e.g. subreg)), to FILE. + (reg XX) rtl is represented as "pXX", of XX was a pseudo, + as "name" it name is the nonnull hardreg name, or as "hXX", if XX + is a hardreg, whose name is NULL, or empty. */ + +static void +ra_print_rtx_object (file, x) + FILE *file; + rtx x; +{ + enum rtx_code code = GET_CODE (x); + enum machine_mode mode = GET_MODE (x); + switch (code) + { + case CONST_INT: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, XWINT (x, 0)); + break; + case CONST_DOUBLE: + { + int i, num = 0; + const char *fmt = GET_RTX_FORMAT (code); + fputs ("dbl(", file); + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + if (num) + fputs (", ", file); + if (fmt[i] == 'e' && XEXP (x, i)) + /* The MEM or other stuff */ + { + ra_print_rtx (file, XEXP (x, i), 0); + num++; + } + else if (fmt[i] == 'w') + { + fprintf (file, HOST_WIDE_INT_PRINT_HEX, XWINT (x, i)); + num++; + } + } + break; + } + case CONST_STRING: fprintf (file, "\"%s\"", XSTR (x, 0)); break; + case CONST: fputs ("const(", file); + ra_print_rtx (file, XEXP (x, 0), 0); + fputs (")", file); + break; + case PC: fputs ("pc", file); break; + case REG: + { + int regno = REGNO (x); + if (regno < FIRST_PSEUDO_REGISTER) + { + int i, nregs = HARD_REGNO_NREGS (regno, mode); + if (nregs > 1) + fputs ("[", file); + for (i = 0; i < nregs; i++) + { + if (i) + fputs (", ", file); + if (reg_names[regno+i] && *reg_names[regno + i]) + fprintf (file, "%s", reg_names[regno + i]); + else + fprintf (file, "h%d", regno + i); + } + if (nregs > 1) + fputs ("]", file); + } + else + fprintf (file, "p%d", regno); + break; + } + case SUBREG: + { + rtx sub = SUBREG_REG (x); + int ofs = SUBREG_BYTE (x); + if (GET_CODE (sub) == REG + && REGNO (sub) < FIRST_PSEUDO_REGISTER) + { + int regno = REGNO (sub); + int i, nregs = HARD_REGNO_NREGS (regno, mode); + regno += subreg_regno_offset (regno, GET_MODE (sub), + ofs, mode); + if (nregs > 1) + fputs ("[", file); + for (i = 0; i < nregs; i++) + { + if (i) + fputs (", ", file); + if (reg_names[regno+i]) + fprintf (file, "%s", reg_names[regno + i]); + else + fprintf (file, "h%d", regno + i); + } + if (nregs > 1) + fputs ("]", file); + } + else + { + ra_print_rtx (file, sub, 0); + fprintf (file, ":[%s+%d]", GET_MODE_NAME (mode), ofs); + } + break; + } + case SCRATCH: fputs ("scratch", file); break; + case CONCAT: ra_print_rtx_2op (file, x); break; + case HIGH: ra_print_rtx_1op (file, x); break; + case LO_SUM: + fputs ("(", file); + ra_print_rtx (file, XEXP (x, 0), 0); + fputs (" + lo(", file); + ra_print_rtx (file, XEXP (x, 1), 0); + fputs ("))", file); + break; + case MEM: fputs ("[", file); + ra_print_rtx (file, XEXP (x, 0), 0); + fprintf (file, "]:%s", GET_MODE_NAME (GET_MODE (x))); + /* XXX print alias set too ?? */ + break; + case LABEL_REF: + { + rtx sub = XEXP (x, 0); + if (GET_CODE (sub) == NOTE + && NOTE_LINE_NUMBER (sub) == NOTE_INSN_DELETED_LABEL) + fprintf (file, "(deleted uid=%d)", INSN_UID (sub)); + else if (GET_CODE (sub) == CODE_LABEL) + fprintf (file, "L%d", CODE_LABEL_NUMBER (sub)); + else + fprintf (file, "(nonlabel uid=%d)", INSN_UID (sub)); + } + break; + case SYMBOL_REF: + fprintf (file, "sym(\"%s\")", XSTR (x, 0)); break; + case CC0: fputs ("cc0", file); break; + default: print_inline_rtx (file, x, 0); break; + } +} + +/* Print a general rtx X to FILE in nice infix form. + If WITH_PN is set, and X is one of the toplevel constructs + (insns, notes, labels or barriers), then print also the UIDs of + the preceding and following insn. */ + +void +ra_print_rtx (file, x, with_pn) + FILE *file; + rtx x; + int with_pn; +{ + enum rtx_code code; + char class; + int unhandled = 0; + if (!x) + return; + code = GET_CODE (x); + class = GET_RTX_CLASS (code); + + /* First handle the insn like constructs. */ + if (INSN_P (x) || code == NOTE || code == CODE_LABEL || code == BARRIER) + { + if (INSN_P (x)) + fputs (" ", file); + /* Non-insns are prefixed by a ';'. */ + if (code == BARRIER) + fputs ("; ", file); + else if (code == NOTE) + /* But notes are indented very far right. */ + fprintf (file, "\t\t\t\t\t; "); + else if (code == CODE_LABEL) + /* And labels have their Lxx name first, before the actual UID. */ + { + fprintf (file, "L%d:\t; ", CODE_LABEL_NUMBER (x)); + if (LABEL_NAME (x)) + fprintf (file, "(%s) ", LABEL_NAME (x)); + switch (LABEL_KIND (x)) + { + case LABEL_NORMAL: break; + case LABEL_STATIC_ENTRY: fputs (" (entry)", file); break; + case LABEL_GLOBAL_ENTRY: fputs (" (global entry)", file); break; + case LABEL_WEAK_ENTRY: fputs (" (weak entry)", file); break; + default: abort(); + } + fprintf (file, " [%d uses] uid=(", LABEL_NUSES (x)); + } + fprintf (file, "%d", INSN_UID (x)); + if (with_pn) + fprintf (file, " %d %d", PREV_INSN (x) ? INSN_UID (PREV_INSN (x)) : 0, + NEXT_INSN (x) ? INSN_UID (NEXT_INSN (x)) : 0); + if (code == BARRIER) + fputs (" -------- barrier ---------", file); + else if (code == CODE_LABEL) + fputs (")", file); + else if (code == NOTE) + { + int ln = NOTE_LINE_NUMBER (x); + if (ln >= (int) NOTE_INSN_BIAS && ln < (int) NOTE_INSN_MAX) + fprintf (file, " %s", GET_NOTE_INSN_NAME (ln)); + else + { + fprintf (file, " line %d", ln); + if (NOTE_SOURCE_FILE (x)) + fprintf (file, ":%s", NOTE_SOURCE_FILE (x)); + } + } + else + { + fprintf (file, "\t"); + ra_print_rtx (file, PATTERN (x), 0); + } + return; + } + switch (code) + { + /* Top-level stuff. */ + case PARALLEL: + { + int j; + for (j = 0; j < XVECLEN (x, 0); j++) + { + if (j) + fputs ("\t;; ", file); + ra_print_rtx (file, XVECEXP (x, 0, j), 0); + } + break; + } + case UNSPEC: case UNSPEC_VOLATILE: + { + int j; + fprintf (file, "unspec%s(%d", + (code == UNSPEC) ? "" : "_vol", XINT (x, 1)); + for (j = 0; j < XVECLEN (x, 0); j++) + { + fputs (", ", file); + ra_print_rtx (file, XVECEXP (x, 0, j), 0); + } + fputs (")", file); + break; + } + case SET: + if (GET_CODE (SET_DEST (x)) == PC) + { + if (GET_CODE (SET_SRC (x)) == IF_THEN_ELSE + && GET_CODE (XEXP (SET_SRC(x), 2)) == PC) + { + fputs ("if ", file); + ra_print_rtx (file, XEXP (SET_SRC (x), 0), 0); + fputs (" jump ", file); + ra_print_rtx (file, XEXP (SET_SRC (x), 1), 0); + } + else + { + fputs ("jump ", file); + ra_print_rtx (file, SET_SRC (x), 0); + } + } + else + { + ra_print_rtx (file, SET_DEST (x), 0); + fputs (" <= ", file); + ra_print_rtx (file, SET_SRC (x), 0); + } + break; + case USE: + fputs ("use <= ", file); + ra_print_rtx (file, XEXP (x, 0), 0); + break; + case CLOBBER: + ra_print_rtx (file, XEXP (x, 0), 0); + fputs (" <= clobber", file); + break; + case CALL: + fputs ("call ", file); + ra_print_rtx (file, XEXP (x, 0), 0); /* Address */ + fputs (" numargs=", file); + ra_print_rtx (file, XEXP (x, 1), 0); /* Num arguments */ + break; + case RETURN: + fputs ("return", file); + break; + case TRAP_IF: + fputs ("if (", file); + ra_print_rtx (file, XEXP (x, 0), 0); + fputs (") trap ", file); + ra_print_rtx (file, XEXP (x, 1), 0); + break; + case RESX: + fprintf (file, "resx from region %d", XINT (x, 0)); + break; + + /* Different things of class 'x' */ + case SUBREG: ra_print_rtx_object (file, x); break; + case STRICT_LOW_PART: + fputs ("low(", file); + ra_print_rtx (file, XEXP (x, 0), 0); + fputs (")", file); + break; + default: + unhandled = 1; + break; + } + if (!unhandled) + return; + if (class == '1') + ra_print_rtx_1op (file, x); + else if (class == '2' || class == 'c' || class == '<') + ra_print_rtx_2op (file, x); + else if (class == '3' || class == 'b') + ra_print_rtx_3op (file, x); + else if (class == 'o') + ra_print_rtx_object (file, x); + else + print_inline_rtx (file, x, 0); +} + +/* This only calls ra_print_rtx(), but emits a final newline. */ + +void +ra_print_rtx_top (file, x, with_pn) + FILE *file; + rtx x; + int with_pn; +{ + ra_print_rtx (file, x, with_pn); + fprintf (file, "\n"); +} + +/* Callable from gdb. This prints rtx X onto stderr. */ + +void +ra_debug_rtx (x) + rtx x; +{ + ra_print_rtx_top (stderr, x, 1); +} + +/* This prints the content of basic block with index BBI. + The first and last insn are emitted with UIDs of prev and next insns. */ + +void +ra_debug_bbi (bbi) + int bbi; +{ + basic_block bb = BASIC_BLOCK (bbi); + rtx insn; + for (insn = bb->head; insn; insn = NEXT_INSN (insn)) + { + ra_print_rtx_top (stderr, insn, (insn == bb->head || insn == bb->end)); + fprintf (stderr, "\n"); + if (insn == bb->end) + break; + } +} + +/* Beginning from INSN, emit NUM insns (if NUM is non-negative) + or emit a window of NUM insns around INSN, to stderr. */ + +void +ra_debug_insns (insn, num) + rtx insn; + int num; +{ + int i, count = (num == 0 ? 1 : num < 0 ? -num : num); + if (num < 0) + for (i = count / 2; i > 0 && PREV_INSN (insn); i--) + insn = PREV_INSN (insn); + for (i = count; i > 0 && insn; insn = NEXT_INSN (insn), i--) + { + if (GET_CODE (insn) == CODE_LABEL) + fprintf (stderr, "\n"); + ra_print_rtx_top (stderr, insn, (i == count || i == 1)); + } +} + +/* Beginning with INSN, emit the whole insn chain into FILE. + This also outputs comments when basic blocks start or end and omits + some notes, if flag_ra_dump_notes is zero. */ + +void +ra_print_rtl_with_bb (file, insn) + FILE *file; + rtx insn; +{ + basic_block last_bb, bb; + unsigned int num = 0; + if (!insn) + fputs ("nil", file); + last_bb = NULL; + for (; insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == BARRIER) + bb = NULL; + else + bb = BLOCK_FOR_INSN (insn); + if (bb != last_bb) + { + if (last_bb) + fprintf (file, ";; End of basic block %d\n", last_bb->index); + if (bb) + fprintf (file, ";; Begin of basic block %d\n", bb->index); + last_bb = bb; + } + if (GET_CODE (insn) == CODE_LABEL) + fputc ('\n', file); + if (GET_CODE (insn) == NOTE) + { + /* Ignore basic block and maybe other notes not referencing + deleted things. */ + if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK + && (flag_ra_dump_notes + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)) + { + ra_print_rtx_top (file, insn, (num == 0 || !NEXT_INSN (insn))); + num++; + } + } + else + { + ra_print_rtx_top (file, insn, (num == 0 || !NEXT_INSN (insn))); + num++; + } + } +} + +/* Count how many insns were seen how often, while building the interference + graph, and prints the findings. */ + +void +dump_number_seen () +{ +#define N 17 + int num[N]; + int i; + + for (i = 0; i < N; i++) + num[i] = 0; + for (i = 0; i < get_max_uid (); i++) + if (number_seen[i] < N - 1) + num[number_seen[i]]++; + else + num[N - 1]++; + for (i = 0; i < N - 1; i++) + if (num[i]) + ra_debug_msg (DUMP_PROCESS, "%d insns seen %d times\n", num[i], i); + if (num[N - 1]) + ra_debug_msg (DUMP_PROCESS, "%d insns seen %d and more times\n", num[i], + N - 1); + ra_debug_msg (DUMP_PROCESS, "from overall %d insns\n", get_max_uid ()); +#undef N +} + +/* Dump the interference graph, the move list and the webs. */ + +void +dump_igraph (df) + struct df *df ATTRIBUTE_UNUSED; +{ + struct move_list *ml; + unsigned int def1, def2; + int num = 0; + int num2; + unsigned int i; + if (!rtl_dump_file || (debug_new_regalloc & (DUMP_IGRAPH | DUMP_WEBS)) == 0) + return; + ra_debug_msg (DUMP_IGRAPH, "conflicts:\n "); + for (def1 = 0; def1 < num_webs; def1++) + { + int num1 = num; + for (num2=0, def2 = 0; def2 < num_webs; def2++) + if (def1 != def2 && TEST_BIT (igraph, igraph_index (def1, def2))) + { + if (num1 == num) + { + if (SUBWEB_P (ID2WEB (def1))) + ra_debug_msg (DUMP_IGRAPH, "%d (SUBREG %d, %d) with ", def1, + ID2WEB (def1)->regno, + SUBREG_BYTE (ID2WEB (def1)->orig_x)); + else + ra_debug_msg (DUMP_IGRAPH, "%d (REG %d) with ", def1, + ID2WEB (def1)->regno); + } + if ((num2 % 9) == 8) + ra_debug_msg (DUMP_IGRAPH, "\n "); + num++; + num2++; + if (SUBWEB_P (ID2WEB (def2))) + ra_debug_msg (DUMP_IGRAPH, "%d(%d,%d) ", def2, ID2WEB (def2)->regno, + SUBREG_BYTE (ID2WEB (def2)->orig_x)); + else + ra_debug_msg (DUMP_IGRAPH, "%d(%d) ", def2, ID2WEB (def2)->regno); + } + if (num1 != num) + ra_debug_msg (DUMP_IGRAPH, "\n "); + } + ra_debug_msg (DUMP_IGRAPH, "\n"); + for (ml = wl_moves; ml; ml = ml->next) + if (ml->move) + { + ra_debug_msg (DUMP_IGRAPH, "move: insn %d: Web %d <-- Web %d\n", + INSN_UID (ml->move->insn), ml->move->target_web->id, + ml->move->source_web->id); + } + ra_debug_msg (DUMP_WEBS, "\nWebs:\n"); + for (i = 0; i < num_webs; i++) + { + struct web *web = ID2WEB (i); + + ra_debug_msg (DUMP_WEBS, " %4d : regno %3d", i, web->regno); + if (SUBWEB_P (web)) + { + ra_debug_msg (DUMP_WEBS, " sub %d", SUBREG_BYTE (web->orig_x)); + ra_debug_msg (DUMP_WEBS, " par %d", find_web_for_subweb (web)->id); + } + ra_debug_msg (DUMP_WEBS, " +%d (span %d, cost ", + web->add_hardregs, web->span_deaths); + ra_debug_msg (DUMP_WEBS, HOST_WIDE_INT_PRINT_DEC, web->spill_cost); + ra_debug_msg (DUMP_WEBS, ") (%s)", reg_class_names[web->regclass]); + if (web->spill_temp == 1) + ra_debug_msg (DUMP_WEBS, " (spilltemp)"); + else if (web->spill_temp == 2) + ra_debug_msg (DUMP_WEBS, " (spilltem2)"); + else if (web->spill_temp == 3) + ra_debug_msg (DUMP_WEBS, " (short)"); + if (web->type == PRECOLORED) + ra_debug_msg (DUMP_WEBS, " (precolored, color=%d)", web->color); + else if (find_web_for_subweb (web)->num_uses == 0) + ra_debug_msg (DUMP_WEBS, " dead"); + if (web->crosses_call) + ra_debug_msg (DUMP_WEBS, " xcall"); + if (web->regno >= max_normal_pseudo) + ra_debug_msg (DUMP_WEBS, " stack"); + ra_debug_msg (DUMP_WEBS, "\n"); + } +} + +/* Dump the interference graph and webs in a format easily + parsable by programs. Used to emit real world interference graph + to my custom graph colorizer. */ + +void +dump_igraph_machine () +{ + unsigned int i; + + if (!rtl_dump_file || (debug_new_regalloc & DUMP_IGRAPH_M) == 0) + return; + ra_debug_msg (DUMP_IGRAPH_M, "g %d %d\n", num_webs - num_subwebs, + FIRST_PSEUDO_REGISTER); + for (i = 0; i < num_webs - num_subwebs; i++) + { + struct web *web = ID2WEB (i); + struct conflict_link *cl; + int flags = 0; + int numc = 0; + int col = 0; + flags = web->spill_temp & 0xF; + flags |= ((web->type == PRECOLORED) ? 1 : 0) << 4; + flags |= (web->add_hardregs & 0xF) << 5; + for (cl = web->conflict_list; cl; cl = cl->next) + if (cl->t->id < web->id) + numc++; + ra_debug_msg (DUMP_IGRAPH_M, "n %d %d %d %d %d %d %d\n", + web->id, web->color, flags, + (unsigned int)web->spill_cost, web->num_defs, web->num_uses, + numc); + if (web->type != PRECOLORED) + { + ra_debug_msg (DUMP_IGRAPH_M, "s %d", web->id); + while (1) + { + unsigned int u = 0; + int n; + for (n = 0; n < 32 && col < FIRST_PSEUDO_REGISTER; n++, col++) + if (TEST_HARD_REG_BIT (web->usable_regs, col)) + u |= 1 << n; + ra_debug_msg (DUMP_IGRAPH_M, " %u", u); + if (col >= FIRST_PSEUDO_REGISTER) + break; + } + ra_debug_msg (DUMP_IGRAPH_M, "\n"); + } + if (numc) + { + ra_debug_msg (DUMP_IGRAPH_M, "c %d", web->id); + for (cl = web->conflict_list; cl; cl = cl->next) + { + if (cl->t->id < web->id) + ra_debug_msg (DUMP_IGRAPH_M, " %d", cl->t->id); + } + ra_debug_msg (DUMP_IGRAPH_M, "\n"); + } + } + ra_debug_msg (DUMP_IGRAPH_M, "e\n"); +} + +/* This runs after colorization and changing the insn stream. + It temporarily replaces all pseudo registers with their colors, + and emits information, if the resulting insns are strictly valid. */ + +void +dump_constraints () +{ + rtx insn; + int i; + if (!rtl_dump_file || (debug_new_regalloc & DUMP_CONSTRAINTS) == 0) + return; + for (i = FIRST_PSEUDO_REGISTER; i < ra_max_regno; i++) + if (regno_reg_rtx[i] && GET_CODE (regno_reg_rtx[i]) == REG) + REGNO (regno_reg_rtx[i]) + = ra_reg_renumber[i] >= 0 ? ra_reg_renumber[i] : i; + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + { + int code; + int uid = INSN_UID (insn); + int o; + /* Don't simply force rerecognition, as combine might left us + with some unrecongnizable ones, which later leads to aborts + in regclass, if we now destroy the remembered INSN_CODE(). */ + /*INSN_CODE (insn) = -1;*/ + code = recog_memoized (insn); + if (code < 0) + { + ra_debug_msg (DUMP_CONSTRAINTS, + "%d: asm insn or not recognizable.\n", uid); + continue; + } + ra_debug_msg (DUMP_CONSTRAINTS, + "%d: code %d {%s}, %d operands, constraints: ", + uid, code, insn_data[code].name, recog_data.n_operands); + extract_insn (insn); + /*preprocess_constraints ();*/ + for (o = 0; o < recog_data.n_operands; o++) + { + ra_debug_msg (DUMP_CONSTRAINTS, + "%d:%s ", o, recog_data.constraints[o]); + } + if (constrain_operands (1)) + ra_debug_msg (DUMP_CONSTRAINTS, "matches strictly alternative %d", + which_alternative); + else + ra_debug_msg (DUMP_CONSTRAINTS, "doesn't match strictly"); + ra_debug_msg (DUMP_CONSTRAINTS, "\n"); + } + for (i = FIRST_PSEUDO_REGISTER; i < ra_max_regno; i++) + if (regno_reg_rtx[i] && GET_CODE (regno_reg_rtx[i]) == REG) + REGNO (regno_reg_rtx[i]) = i; +} + +/* This counts and emits the cumulated cost of all spilled webs, + preceded by a custom message MSG, with debug level LEVEL. */ + +void +dump_graph_cost (level, msg) + unsigned int level; + const char *msg; +{ + unsigned int i; + unsigned HOST_WIDE_INT cost; + if (!rtl_dump_file || (debug_new_regalloc & level) == 0) + return; + + cost = 0; + for (i = 0; i < num_webs; i++) + { + struct web *web = id2web[i]; + if (alias (web)->type == SPILLED) + cost += web->orig_spill_cost; + } + ra_debug_msg (level, " spill cost of graph (%s) = ", msg ? msg : ""); + ra_debug_msg (level, HOST_WIDE_INT_PRINT_UNSIGNED, cost); + ra_debug_msg (level, "\n"); +} + +/* Dump the color assignment per web, the coalesced and spilled webs. */ + +void +dump_ra (df) + struct df *df ATTRIBUTE_UNUSED; +{ + struct web *web; + struct dlist *d; + if (!rtl_dump_file || (debug_new_regalloc & DUMP_RESULTS) == 0) + return; + + ra_debug_msg (DUMP_RESULTS, "\nColored:\n"); + for (d = WEBS(COLORED); d; d = d->next) + { + web = DLIST_WEB (d); + ra_debug_msg (DUMP_RESULTS, " %4d : color %d\n", web->id, web->color); + } + ra_debug_msg (DUMP_RESULTS, "\nCoalesced:\n"); + for (d = WEBS(COALESCED); d; d = d->next) + { + web = DLIST_WEB (d); + ra_debug_msg (DUMP_RESULTS, " %4d : to web %d, color %d\n", web->id, + alias (web)->id, web->color); + } + ra_debug_msg (DUMP_RESULTS, "\nSpilled:\n"); + for (d = WEBS(SPILLED); d; d = d->next) + { + web = DLIST_WEB (d); + ra_debug_msg (DUMP_RESULTS, " %4d\n", web->id); + } + ra_debug_msg (DUMP_RESULTS, "\n"); + dump_cost (DUMP_RESULTS); +} + +/* Calculate and dump the cumulated costs of certain types of insns + (loads, stores and copies). */ + +void +dump_static_insn_cost (file, message, prefix) + FILE *file; + const char *message; + const char *prefix; +{ + struct cost + { + unsigned HOST_WIDE_INT cost; + unsigned int count; + }; + basic_block bb; + struct cost load, store, regcopy, selfcopy, overall; + memset (&load, 0, sizeof(load)); + memset (&store, 0, sizeof(store)); + memset (®copy, 0, sizeof(regcopy)); + memset (&selfcopy, 0, sizeof(selfcopy)); + memset (&overall, 0, sizeof(overall)); + + if (!file) + return; + + FOR_EACH_BB (bb) + { + unsigned HOST_WIDE_INT block_cost = bb->frequency; + rtx insn, set; + for (insn = bb->head; insn; insn = NEXT_INSN (insn)) + { + /* Yes, yes. We don't calculate the costs precisely. + Only for "simple enough" insns. Those containing single + sets only. */ + if (INSN_P (insn) && ((set = single_set (insn)) != NULL)) + { + rtx src = SET_SRC (set); + rtx dest = SET_DEST (set); + struct cost *pcost = NULL; + overall.cost += block_cost; + overall.count++; + if (rtx_equal_p (src, dest)) + pcost = &selfcopy; + else if (GET_CODE (src) == GET_CODE (dest) + && ((GET_CODE (src) == REG) + || (GET_CODE (src) == SUBREG + && GET_CODE (SUBREG_REG (src)) == REG + && GET_CODE (SUBREG_REG (dest)) == REG))) + pcost = ®copy; + else + { + if (GET_CODE (src) == SUBREG) + src = SUBREG_REG (src); + if (GET_CODE (dest) == SUBREG) + dest = SUBREG_REG (dest); + if (GET_CODE (src) == MEM && GET_CODE (dest) != MEM + && memref_is_stack_slot (src)) + pcost = &load; + else if (GET_CODE (src) != MEM && GET_CODE (dest) == MEM + && memref_is_stack_slot (dest)) + pcost = &store; + } + if (pcost) + { + pcost->cost += block_cost; + pcost->count++; + } + } + if (insn == bb->end) + break; + } + } + + if (!prefix) + prefix = ""; + fprintf (file, "static insn cost %s\n", message ? message : ""); + fprintf (file, " %soverall:\tnum=%6d\tcost=", prefix, overall.count); + fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, overall.cost); + fprintf (file, "\n"); + fprintf (file, " %sloads:\tnum=%6d\tcost=", prefix, load.count); + fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, load.cost); + fprintf (file, "\n"); + fprintf (file, " %sstores:\tnum=%6d\tcost=", prefix, store.count); + fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, store.cost); + fprintf (file, "\n"); + fprintf (file, " %sregcopy:\tnum=%6d\tcost=", prefix, regcopy.count); + fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, regcopy.cost); + fprintf (file, "\n"); + fprintf (file, " %sselfcpy:\tnum=%6d\tcost=", prefix, selfcopy.count); + fprintf (file, HOST_WIDE_INT_PRINT_DEC_SPACE, 8, selfcopy.cost); + fprintf (file, "\n"); +} + +/* Returns nonzero, if WEB1 and WEB2 have some possible + hardregs in common. */ + +int +web_conflicts_p (web1, web2) + struct web *web1; + struct web *web2; +{ + if (web1->type == PRECOLORED && web2->type == PRECOLORED) + return 0; + + if (web1->type == PRECOLORED) + return TEST_HARD_REG_BIT (web2->usable_regs, web1->regno); + + if (web2->type == PRECOLORED) + return TEST_HARD_REG_BIT (web1->usable_regs, web2->regno); + + return hard_regs_intersect_p (&web1->usable_regs, &web2->usable_regs); +} + +/* Dump all uids of insns in which WEB is mentioned. */ + +void +dump_web_insns (web) + struct web *web; +{ + unsigned int i; + + ra_debug_msg (DUMP_EVER, "Web: %i(%i)+%i class: %s freedom: %i degree %i\n", + web->id, web->regno, web->add_hardregs, + reg_class_names[web->regclass], + web->num_freedom, web->num_conflicts); + ra_debug_msg (DUMP_EVER, " def insns:"); + + for (i = 0; i < web->num_defs; ++i) + { + ra_debug_msg (DUMP_EVER, " %d ", INSN_UID (web->defs[i]->insn)); + } + + ra_debug_msg (DUMP_EVER, "\n use insns:"); + for (i = 0; i < web->num_uses; ++i) + { + ra_debug_msg (DUMP_EVER, " %d ", INSN_UID (web->uses[i]->insn)); + } + ra_debug_msg (DUMP_EVER, "\n"); +} + +/* Dump conflicts for web WEB. */ + +void +dump_web_conflicts (web) + struct web *web; +{ + int num = 0; + unsigned int def2; + + ra_debug_msg (DUMP_EVER, "Web: %i(%i)+%i class: %s freedom: %i degree %i\n", + web->id, web->regno, web->add_hardregs, + reg_class_names[web->regclass], + web->num_freedom, web->num_conflicts); + + for (def2 = 0; def2 < num_webs; def2++) + if (TEST_BIT (igraph, igraph_index (web->id, def2)) && web->id != def2) + { + if ((num % 9) == 5) + ra_debug_msg (DUMP_EVER, "\n "); + num++; + + ra_debug_msg (DUMP_EVER, " %d(%d)", def2, id2web[def2]->regno); + if (id2web[def2]->add_hardregs) + ra_debug_msg (DUMP_EVER, "+%d", id2web[def2]->add_hardregs); + + if (web_conflicts_p (web, id2web[def2])) + ra_debug_msg (DUMP_EVER, "/x"); + + if (id2web[def2]->type == SELECT) + ra_debug_msg (DUMP_EVER, "/s"); + + if (id2web[def2]->type == COALESCED) + ra_debug_msg (DUMP_EVER,"/c/%d", alias (id2web[def2])->id); + } + ra_debug_msg (DUMP_EVER, "\n"); + { + struct conflict_link *wl; + num = 0; + ra_debug_msg (DUMP_EVER, "By conflicts: "); + for (wl = web->conflict_list; wl; wl = wl->next) + { + struct web* w = wl->t; + if ((num % 9) == 8) + ra_debug_msg (DUMP_EVER, "\n "); + num++; + ra_debug_msg (DUMP_EVER, "%d(%d)%s ", w->id, w->regno, + web_conflicts_p (web, w) ? "+" : ""); + } + ra_debug_msg (DUMP_EVER, "\n"); + } +} + +/* Output HARD_REG_SET to stderr. */ + +void +debug_hard_reg_set (set) + HARD_REG_SET set; +{ + int i; + for (i=0; i < FIRST_PSEUDO_REGISTER; ++i) + { + if (TEST_HARD_REG_BIT (set, i)) + { + fprintf (stderr, "%s ", reg_names[i]); + } + } + fprintf (stderr, "\n"); +} + +/* +vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: +*/ |