URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [sched-vis.c] - Rev 768
Go to most recent revision | Compare with Previous | Blame | View Log
/* Instruction scheduling pass. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.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 3, 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 COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "rtl.h" #include "obstack.h" #include "hard-reg-set.h" #include "basic-block.h" #include "insn-attr.h" #include "sched-int.h" #include "tree-pass.h" static char *safe_concat (char *, char *, const char *); #define BUF_LEN 2048 static char * safe_concat (char *buf, char *cur, const char *str) { char *end = buf + BUF_LEN - 2; /* Leave room for null. */ int c; if (cur > end) { *end = '\0'; return end; } while (cur < end && (c = *str++) != '\0') *cur++ = c; *cur = '\0'; return cur; } /* This recognizes rtx, I classified as expressions. These are always represent some action on values or results of other expression, that may be stored in objects representing values. */ static void print_exp (char *buf, const_rtx x, int verbose) { char tmp[BUF_LEN]; const char *st[4]; char *cur = buf; const char *fun = (char *) 0; const char *sep; rtx op[4]; int i; for (i = 0; i < 4; i++) { st[i] = (char *) 0; op[i] = NULL_RTX; } switch (GET_CODE (x)) { case PLUS: op[0] = XEXP (x, 0); if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) < 0) { st[1] = "-"; op[1] = GEN_INT (-INTVAL (XEXP (x, 1))); } else { st[1] = "+"; op[1] = XEXP (x, 1); } break; case LO_SUM: op[0] = XEXP (x, 0); st[1] = "+low("; op[1] = XEXP (x, 1); st[2] = ")"; break; case MINUS: op[0] = XEXP (x, 0); st[1] = "-"; op[1] = XEXP (x, 1); break; case COMPARE: fun = "cmp"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case NEG: st[0] = "-"; op[0] = XEXP (x, 0); break; case MULT: op[0] = XEXP (x, 0); st[1] = "*"; op[1] = XEXP (x, 1); break; case DIV: op[0] = XEXP (x, 0); st[1] = "/"; op[1] = XEXP (x, 1); break; case UDIV: fun = "udiv"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case MOD: op[0] = XEXP (x, 0); st[1] = "%"; op[1] = XEXP (x, 1); break; case UMOD: fun = "umod"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case SMIN: fun = "smin"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case SMAX: fun = "smax"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case UMIN: fun = "umin"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case UMAX: fun = "umax"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case NOT: st[0] = "!"; op[0] = XEXP (x, 0); break; case AND: op[0] = XEXP (x, 0); st[1] = "&"; op[1] = XEXP (x, 1); break; case IOR: op[0] = XEXP (x, 0); st[1] = "|"; op[1] = XEXP (x, 1); break; case XOR: op[0] = XEXP (x, 0); st[1] = "^"; op[1] = XEXP (x, 1); break; case ASHIFT: op[0] = XEXP (x, 0); st[1] = "<<"; op[1] = XEXP (x, 1); break; case LSHIFTRT: op[0] = XEXP (x, 0); st[1] = " 0>>"; op[1] = XEXP (x, 1); break; case ASHIFTRT: op[0] = XEXP (x, 0); st[1] = ">>"; op[1] = XEXP (x, 1); break; case ROTATE: op[0] = XEXP (x, 0); st[1] = "<-<"; op[1] = XEXP (x, 1); break; case ROTATERT: op[0] = XEXP (x, 0); st[1] = ">->"; op[1] = XEXP (x, 1); break; case ABS: fun = "abs"; op[0] = XEXP (x, 0); break; case SQRT: fun = "sqrt"; op[0] = XEXP (x, 0); break; case FFS: fun = "ffs"; op[0] = XEXP (x, 0); break; case EQ: op[0] = XEXP (x, 0); st[1] = "=="; op[1] = XEXP (x, 1); break; case NE: op[0] = XEXP (x, 0); st[1] = "!="; op[1] = XEXP (x, 1); break; case GT: op[0] = XEXP (x, 0); st[1] = ">"; op[1] = XEXP (x, 1); break; case GTU: fun = "gtu"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case LT: op[0] = XEXP (x, 0); st[1] = "<"; op[1] = XEXP (x, 1); break; case LTU: fun = "ltu"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case GE: op[0] = XEXP (x, 0); st[1] = ">="; op[1] = XEXP (x, 1); break; case GEU: fun = "geu"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case LE: op[0] = XEXP (x, 0); st[1] = "<="; op[1] = XEXP (x, 1); break; case LEU: fun = "leu"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); break; case SIGN_EXTRACT: fun = (verbose) ? "sign_extract" : "sxt"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); op[2] = XEXP (x, 2); break; case ZERO_EXTRACT: fun = (verbose) ? "zero_extract" : "zxt"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); op[2] = XEXP (x, 2); break; case SIGN_EXTEND: fun = (verbose) ? "sign_extend" : "sxn"; op[0] = XEXP (x, 0); break; case ZERO_EXTEND: fun = (verbose) ? "zero_extend" : "zxn"; op[0] = XEXP (x, 0); break; case FLOAT_EXTEND: fun = (verbose) ? "float_extend" : "fxn"; op[0] = XEXP (x, 0); break; case TRUNCATE: fun = (verbose) ? "trunc" : "trn"; op[0] = XEXP (x, 0); break; case FLOAT_TRUNCATE: fun = (verbose) ? "float_trunc" : "ftr"; op[0] = XEXP (x, 0); break; case FLOAT: fun = (verbose) ? "float" : "flt"; op[0] = XEXP (x, 0); break; case UNSIGNED_FLOAT: fun = (verbose) ? "uns_float" : "ufl"; op[0] = XEXP (x, 0); break; case FIX: fun = "fix"; op[0] = XEXP (x, 0); break; case UNSIGNED_FIX: fun = (verbose) ? "uns_fix" : "ufx"; op[0] = XEXP (x, 0); break; case PRE_DEC: st[0] = "--"; op[0] = XEXP (x, 0); break; case PRE_INC: st[0] = "++"; op[0] = XEXP (x, 0); break; case POST_DEC: op[0] = XEXP (x, 0); st[1] = "--"; break; case POST_INC: op[0] = XEXP (x, 0); st[1] = "++"; break; case PRE_MODIFY: st[0] = "pre "; op[0] = XEXP (XEXP (x, 1), 0); st[1] = "+="; op[1] = XEXP (XEXP (x, 1), 1); break; case POST_MODIFY: st[0] = "post "; op[0] = XEXP (XEXP (x, 1), 0); st[1] = "+="; op[1] = XEXP (XEXP (x, 1), 1); break; case CALL: st[0] = "call "; op[0] = XEXP (x, 0); if (verbose) { st[1] = " argc:"; op[1] = XEXP (x, 1); } break; case IF_THEN_ELSE: st[0] = "{("; op[0] = XEXP (x, 0); st[1] = ")?"; op[1] = XEXP (x, 1); st[2] = ":"; op[2] = XEXP (x, 2); st[3] = "}"; break; case TRAP_IF: fun = "trap_if"; op[0] = TRAP_CONDITION (x); break; case PREFETCH: fun = "prefetch"; op[0] = XEXP (x, 0); op[1] = XEXP (x, 1); op[2] = XEXP (x, 2); break; case UNSPEC: case UNSPEC_VOLATILE: { cur = safe_concat (buf, cur, "unspec"); if (GET_CODE (x) == UNSPEC_VOLATILE) cur = safe_concat (buf, cur, "/v"); cur = safe_concat (buf, cur, "["); sep = ""; for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (tmp, XVECEXP (x, 0, i), verbose); cur = safe_concat (buf, cur, sep); cur = safe_concat (buf, cur, tmp); sep = ","; } cur = safe_concat (buf, cur, "] "); sprintf (tmp, "%d", XINT (x, 1)); cur = safe_concat (buf, cur, tmp); } break; default: /* If (verbose) debug_rtx (x); */ st[0] = GET_RTX_NAME (GET_CODE (x)); break; } /* Print this as a function? */ if (fun) { cur = safe_concat (buf, cur, fun); cur = safe_concat (buf, cur, "("); } for (i = 0; i < 4; i++) { if (st[i]) cur = safe_concat (buf, cur, st[i]); if (op[i]) { if (fun && i != 0) cur = safe_concat (buf, cur, ","); print_value (tmp, op[i], verbose); cur = safe_concat (buf, cur, tmp); } } if (fun) cur = safe_concat (buf, cur, ")"); } /* print_exp */ /* Prints rtxes, I customarily classified as values. They're constants, registers, labels, symbols and memory accesses. */ void print_value (char *buf, const_rtx x, int verbose) { char t[BUF_LEN]; char *cur = buf; if (!x) { safe_concat (buf, buf, "(nil)"); return; } switch (GET_CODE (x)) { case CONST_INT: sprintf (t, HOST_WIDE_INT_PRINT_HEX, (unsigned HOST_WIDE_INT) INTVAL (x)); cur = safe_concat (buf, cur, t); break; case CONST_DOUBLE: if (FLOAT_MODE_P (GET_MODE (x))) real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1); else sprintf (t, "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX ">", (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x), (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x)); cur = safe_concat (buf, cur, t); break; case CONST_FIXED: fixed_to_decimal (t, CONST_FIXED_VALUE (x), sizeof (t)); cur = safe_concat (buf, cur, t); break; case CONST_STRING: cur = safe_concat (buf, cur, "\""); cur = safe_concat (buf, cur, XSTR (x, 0)); cur = safe_concat (buf, cur, "\""); break; case SYMBOL_REF: cur = safe_concat (buf, cur, "`"); cur = safe_concat (buf, cur, XSTR (x, 0)); cur = safe_concat (buf, cur, "'"); break; case LABEL_REF: sprintf (t, "L%d", INSN_UID (XEXP (x, 0))); cur = safe_concat (buf, cur, t); break; case CONST: print_value (t, XEXP (x, 0), verbose); cur = safe_concat (buf, cur, "const("); cur = safe_concat (buf, cur, t); cur = safe_concat (buf, cur, ")"); break; case HIGH: print_value (t, XEXP (x, 0), verbose); cur = safe_concat (buf, cur, "high("); cur = safe_concat (buf, cur, t); cur = safe_concat (buf, cur, ")"); break; case REG: if (REGNO (x) < FIRST_PSEUDO_REGISTER) { int c = reg_names[REGNO (x)][0]; if (ISDIGIT (c)) cur = safe_concat (buf, cur, "%"); cur = safe_concat (buf, cur, reg_names[REGNO (x)]); } else { sprintf (t, "r%d", REGNO (x)); cur = safe_concat (buf, cur, t); } if (verbose #ifdef INSN_SCHEDULING && !current_sched_info #endif ) { sprintf (t, ":%s", GET_MODE_NAME (GET_MODE (x))); cur = safe_concat (buf, cur, t); } break; case SUBREG: print_value (t, SUBREG_REG (x), verbose); cur = safe_concat (buf, cur, t); sprintf (t, "#%d", SUBREG_BYTE (x)); cur = safe_concat (buf, cur, t); break; case STRICT_LOW_PART: print_value (t, XEXP (x, 0), verbose); cur = safe_concat (buf, cur, "strict_low_part("); cur = safe_concat (buf, cur, t); cur = safe_concat (buf, cur, ")"); break; case SCRATCH: cur = safe_concat (buf, cur, "scratch"); break; case CC0: cur = safe_concat (buf, cur, "cc0"); break; case PC: cur = safe_concat (buf, cur, "pc"); break; case MEM: print_value (t, XEXP (x, 0), verbose); cur = safe_concat (buf, cur, "["); cur = safe_concat (buf, cur, t); cur = safe_concat (buf, cur, "]"); break; case DEBUG_EXPR: sprintf (t, "D#%i", DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))); cur = safe_concat (buf, cur, t); break; default: print_exp (t, x, verbose); cur = safe_concat (buf, cur, t); break; } } /* print_value */ /* The next step in insn detalization, its pattern recognition. */ void print_pattern (char *buf, const_rtx x, int verbose) { char t1[BUF_LEN], t2[BUF_LEN], t3[BUF_LEN]; switch (GET_CODE (x)) { case SET: print_value (t1, SET_DEST (x), verbose); print_value (t2, SET_SRC (x), verbose); sprintf (buf, "%s=%s", t1, t2); break; case RETURN: sprintf (buf, "return"); break; case SIMPLE_RETURN: sprintf (buf, "simple_return"); break; case CALL: print_exp (buf, x, verbose); break; case CLOBBER: print_value (t1, XEXP (x, 0), verbose); sprintf (buf, "clobber %s", t1); break; case USE: print_value (t1, XEXP (x, 0), verbose); sprintf (buf, "use %s", t1); break; case VAR_LOCATION: print_value (t1, PAT_VAR_LOCATION_LOC (x), verbose); sprintf (buf, "loc %s", t1); break; case COND_EXEC: if (GET_CODE (COND_EXEC_TEST (x)) == NE && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) print_value (t1, XEXP (COND_EXEC_TEST (x), 0), verbose); else if (GET_CODE (COND_EXEC_TEST (x)) == EQ && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) { t1[0] = '!'; print_value (t1 + 1, XEXP (COND_EXEC_TEST (x), 0), verbose); } else print_value (t1, COND_EXEC_TEST (x), verbose); print_pattern (t2, COND_EXEC_CODE (x), verbose); sprintf (buf, "(%s) %s", t1, t2); break; case PARALLEL: { int i; sprintf (t1, "{"); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (t2, XVECEXP (x, 0, i), verbose); sprintf (t3, "%s%s;", t1, t2); strcpy (t1, t3); } sprintf (buf, "%s}", t1); } break; case SEQUENCE: /* Should never see SEQUENCE codes until after reorg. */ gcc_unreachable (); case ASM_INPUT: sprintf (buf, "asm {%s}", XSTR (x, 0)); break; case ADDR_VEC: /* Fall through. */ case ADDR_DIFF_VEC: print_value (buf, XEXP (x, 0), verbose); break; case TRAP_IF: print_value (t1, TRAP_CONDITION (x), verbose); sprintf (buf, "trap_if %s", t1); break; case UNSPEC: { int i; sprintf (t1, "unspec{"); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (t2, XVECEXP (x, 0, i), verbose); sprintf (t3, "%s%s;", t1, t2); strcpy (t1, t3); } sprintf (buf, "%s}", t1); } break; case UNSPEC_VOLATILE: { int i; sprintf (t1, "unspec/v{"); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (t2, XVECEXP (x, 0, i), verbose); sprintf (t3, "%s%s;", t1, t2); strcpy (t1, t3); } sprintf (buf, "%s}", t1); } break; default: print_value (buf, x, verbose); } } /* print_pattern */ /* This is the main function in rtl visualization mechanism. It accepts an rtx and tries to recognize it as an insn, then prints it properly in human readable form, resembling assembler mnemonics. For every insn it prints its UID and BB the insn belongs too. (Probably the last "option" should be extended somehow, since it depends now on sched.c inner variables ...) */ void print_insn (char *buf, const_rtx x, int verbose) { char t[BUF_LEN]; const_rtx insn = x; switch (GET_CODE (x)) { case INSN: print_pattern (t, PATTERN (x), verbose); #ifdef INSN_SCHEDULING if (verbose && current_sched_info) sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1), t); else #endif sprintf (buf, " %4d %s", INSN_UID (x), t); break; case DEBUG_INSN: { const char *name = "?"; if (DECL_P (INSN_VAR_LOCATION_DECL (insn))) { tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (insn)); char idbuf[32]; if (id) name = IDENTIFIER_POINTER (id); else if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == DEBUG_EXPR_DECL) { sprintf (idbuf, "D#%i", DEBUG_TEMP_UID (INSN_VAR_LOCATION_DECL (insn))); name = idbuf; } else { sprintf (idbuf, "D.%i", DECL_UID (INSN_VAR_LOCATION_DECL (insn))); name = idbuf; } } if (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn))) sprintf (buf, " %4d: debug %s optimized away", INSN_UID (insn), name); else { print_pattern (t, INSN_VAR_LOCATION_LOC (insn), verbose); sprintf (buf, " %4d: debug %s => %s", INSN_UID (insn), name, t); } } break; case JUMP_INSN: print_pattern (t, PATTERN (x), verbose); #ifdef INSN_SCHEDULING if (verbose && current_sched_info) sprintf (buf, "%s: jump %s", (*current_sched_info->print_insn) (x, 1), t); else #endif sprintf (buf, " %4d %s", INSN_UID (x), t); break; case CALL_INSN: x = PATTERN (insn); if (GET_CODE (x) == PARALLEL) { x = XVECEXP (x, 0, 0); print_pattern (t, x, verbose); } else strcpy (t, "call <...>"); #ifdef INSN_SCHEDULING if (verbose && current_sched_info) sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (insn, 1), t); else #endif sprintf (buf, " %4d %s", INSN_UID (insn), t); break; case CODE_LABEL: sprintf (buf, "L%d:", INSN_UID (x)); break; case BARRIER: sprintf (buf, "i%4d: barrier", INSN_UID (x)); break; case NOTE: sprintf (buf, " %4d %s", INSN_UID (x), GET_NOTE_INSN_NAME (NOTE_KIND (x))); break; default: sprintf (buf, "i%4d <What %s?>", INSN_UID (x), GET_RTX_NAME (GET_CODE (x))); } } /* print_insn */ /* Emit a slim dump of X (an insn) to the file F, including any register note attached to the instruction. */ void dump_insn_slim (FILE *f, rtx x) { char t[BUF_LEN + 32]; rtx note; print_insn (t, x, 1); fputs (t, f); putc ('\n', f); if (INSN_P (x) && REG_NOTES (x)) for (note = REG_NOTES (x); note; note = XEXP (note, 1)) { print_value (t, XEXP (note, 0), 1); fprintf (f, " %s: %s\n", GET_REG_NOTE_NAME (REG_NOTE_KIND (note)), t); } } /* Emit a slim dump of X (an insn) to stderr. */ DEBUG_FUNCTION void debug_insn_slim (rtx x) { dump_insn_slim (stderr, x); } /* Provide a slim dump the instruction chain starting at FIRST to F, honoring the dump flags given in FLAGS. Currently, TDF_BLOCKS and TDF_DETAILS include more information on the basic blocks. */ void print_rtl_slim_with_bb (FILE *f, rtx first, int flags) { print_rtl_slim (f, first, NULL, -1, flags); } /* Same as above, but stop at LAST or when COUNT == 0. If COUNT < 0 it will stop only at LAST or NULL rtx. */ void print_rtl_slim (FILE *f, rtx first, rtx last, int count, int flags) { basic_block current_bb = NULL; rtx insn, tail; tail = last ? NEXT_INSN (last) : NULL_RTX; for (insn = first; (insn != NULL) && (insn != tail) && (count != 0); insn = NEXT_INSN (insn)) { if ((flags & TDF_BLOCKS) && (INSN_P (insn) || NOTE_P (insn)) && BLOCK_FOR_INSN (insn) && !current_bb) { current_bb = BLOCK_FOR_INSN (insn); dump_bb_info (current_bb, true, false, flags, ";; ", f); } dump_insn_slim (f, insn); if ((flags & TDF_BLOCKS) && current_bb && insn == BB_END (current_bb)) { dump_bb_info (current_bb, false, true, flags, ";; ", f); current_bb = NULL; } if (count > 0) count--; } } DEBUG_FUNCTION void debug_bb_slim (struct basic_block_def *bb) { print_rtl_slim (stderr, BB_HEAD (bb), BB_END (bb), -1, 32); } DEBUG_FUNCTION void debug_bb_n_slim (int n) { struct basic_block_def *bb = BASIC_BLOCK (n); debug_bb_slim (bb); }
Go to most recent revision | Compare with Previous | Blame | View Log