| /* Instruction scheduling pass. |
| Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
| 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 "real.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 (GET_CODE (XEXP (x, 1)) == CONST_INT |
| && 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; |
| |
| 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 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; |
| 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 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 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: |
| break; |
| 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 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. */ |
| 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) || GET_CODE (insn) == NOTE) |
| && 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--; |
| } |
| } |
| |
| void |
| debug_bb_slim (struct basic_block_def *bb) |
| { |
| print_rtl_slim (stderr, BB_HEAD (bb), BB_END (bb), -1, 32); |
| } |
| |
| void |
| debug_bb_n_slim (int n) |
| { |
| struct basic_block_def *bb = BASIC_BLOCK (n); |
| debug_bb_slim (bb); |
| } |
| |