📄 rtlanal.c
字号:
/* Analyze RTL for C-Compiler Copyright (C) 1987, 1988 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "config.h"#include "rtl.h"extern void note_stores ();static int reg_set_p ();/* Return 1 if the value of X is unstable (would be different at a different point in the program). The frame pointer, arg pointer, etc. are considered stable (within one function) and so is anything marked `unchanging'. */intrtx_unstable_p (x) rtx x;{ register RTX_CODE code = GET_CODE (x); register int i; register char *fmt; if (code == MEM) return ! RTX_UNCHANGING_P (x); if (code == QUEUED) return 1; if (code == CONST || code == CONST_INT) return 0; if (code == REG) return ! (REGNO (x) == FRAME_POINTER_REGNUM || REGNO (x) == ARG_POINTER_REGNUM || RTX_UNCHANGING_P (x)); fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') if (rtx_unstable_p (XEXP (x, i))) return 1; return 0;}/* Return 1 if X has a value that can vary even between two executions of the program. 0 means X can be compared reliably against certain constants or near-constants. The frame pointer and the arg pointer are considered constant. */intrtx_varies_p (x) rtx x;{ register RTX_CODE code = GET_CODE (x); register int i; register char *fmt; if (code == MEM) return 1; if (code == QUEUED) return 1; if (code == CONST || code == CONST_INT) return 0; if (code == REG) return ! (REGNO (x) == FRAME_POINTER_REGNUM || REGNO (x) == ARG_POINTER_REGNUM); fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') if (rtx_varies_p (XEXP (x, i))) return 1; return 0;}/* Return 1 if X refers to a memory location whose address cannot be compared reliably with constant addresses, or if X refers to a BLKmode memory object. */intrtx_addr_varies_p (x) rtx x;{ register enum rtx_code code; register int i; register char *fmt; if (x == 0) return 0; code = GET_CODE (x); if (code == MEM) return GET_MODE (x) == BLKmode || rtx_varies_p (XEXP (x, 0)); fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') if (rtx_addr_varies_p (XEXP (x, i))) return 1; return 0;}/* Nonzero if register REG appears somewhere within IN. Also works if REG is not a register; in this case it checks for a subexpression of IN that is Lisp "equal" to REG. */intreg_mentioned_p (reg, in) register rtx reg, in;{ register char *fmt; register int i; register enum rtx_code code; if (in == 0) return 0; if (reg == in) return 1; code = GET_CODE (in); switch (code) { /* Compare registers by number. */ case REG: return GET_CODE (reg) == REG && REGNO (in) == REGNO (reg); /* These codes have no constituent expressions and are unique. */ case CC0: case PC: return 0; case CONST_INT: return GET_CODE (reg) == CONST_INT && INTVAL (in) == INTVAL (reg); } if (GET_CODE (reg) == code && rtx_equal_p (reg, in)) return 1; fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'E') { register int j; for (j = XVECLEN (in, i) - 1; j >= 0; j--) if (reg_mentioned_p (reg, XVECEXP (in, i, j))) return 1; } else if (fmt[i] == 'e' && reg_mentioned_p (reg, XEXP (in, i))) return 1; } return 0;}/* Nonzero if register REG is used in an insn between FROM_INSN and TO_INSN (exclusive of those two). */intreg_used_between_p (reg, from_insn, to_insn) rtx reg, from_insn, to_insn;{ register rtx insn; register RTX_CODE code; for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn)) if (((code = GET_CODE (insn)) == INSN || code == JUMP_INSN || code == CALL_INSN) && reg_mentioned_p (reg, PATTERN (insn))) return 1; return 0;}/* Nonzero if register REG is set or clobbered in an insn between FROM_INSN and TO_INSN (exclusive of those two). Does not notice increments, only SET and CLOBBER. */intreg_set_between_p (reg, from_insn, to_insn) rtx reg, from_insn, to_insn;{ register rtx insn; register RTX_CODE code; for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn)) if (((code = GET_CODE (insn)) == INSN || code == JUMP_INSN || code == CALL_INSN) && reg_set_p (reg, PATTERN (insn))) return 1; return 0;}/* Internals of reg_set_between_p. */static rtx reg_set_reg;static int reg_set_flag;static voidreg_set_p_1 (x) rtx x;{ if (reg_overlap_mentioned_p (reg_set_reg, x)) reg_set_flag = 1;}static intreg_set_p (reg, insn) rtx reg, insn;{ reg_set_reg = reg; reg_set_flag = 0; note_stores (insn, reg_set_p_1); return reg_set_flag;}/* Return nonzero if hard register in range [REGNO, ENDREGNO) appears either explicitly or implicitly in X other than being stored into. References contained within the substructure at LOC do not count. LOC may be zero, meaning don't ignore anything. */intrefers_to_regno_p (regno, endregno, x, loc) int regno, endregno; rtx x; rtx *loc;{ register int i; register RTX_CODE code; register char *fmt; repeat: code = GET_CODE (x); if (code == REG) { i = REGNO (x); return (endregno > i && regno < i + HARD_REGNO_NREGS (i, GET_MODE (x))); } if (code == SET) { /* Note setting a SUBREG counts as referring to the REG it is in! */ if (GET_CODE (SET_DEST (x)) != REG && refers_to_regno_p (regno, endregno, SET_DEST (x), loc)) return 1; if (loc == &SET_SRC (x)) return 0; x = SET_SRC (x); goto repeat; } if (code == CLOBBER) { if (GET_CODE (SET_DEST (x)) != REG && refers_to_regno_p (regno, endregno, SET_DEST (x), loc)) return 1; return 0; } /* X does not match, so try its subexpressions. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && loc != &XEXP (x, i)) { if (i == 0) { x = XEXP (x, 0); goto repeat; } else if (refers_to_regno_p (regno, endregno, XEXP (x, i), loc)) return 1; } else if (fmt[i] == 'E') { register int j; for (j = XVECLEN (x, i) - 1; j >=0; j--) if (loc != &XVECEXP (x, i, j) && refers_to_regno_p (regno, endregno, XVECEXP (x, i, j), loc)) return 1; } } return 0;}/* Nonzero if X contains any reg that overlaps hard register REG. */intreg_overlap_mentioned_p (reg, x) rtx reg, x;{ int regno = REGNO (reg); int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); return refers_to_regno_p (regno, endregno, x, 0);}/* This is 1 until after reload pass. */int rtx_equal_function_value_matters;/* Return 1 if X and Y are identical-looking rtx's. This is the Lisp function EQUAL for rtx arguments. */intrtx_equal_p (x, y) rtx x, y;{ register int i; register int j; register enum rtx_code code; register char *fmt; if (x == y) return 1; if (x == 0 || y == 0) return 0; code = GET_CODE (x); /* Rtx's of different codes cannot be equal. */ if (code != GET_CODE (y)) return 0; /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. (REG:SI x) and (REG:HI x) are NOT equivalent. */ if (GET_MODE (x) != GET_MODE (y)) return 0; /* These three types of rtx's can be compared nonrecursively. */ /* Until the end of reload, don't consider the a reference to the return register of the current function the same as the return from a called function. This eases the job of function integration. Once the distinction no longer matters, the insn will be deleted. */ if (code == REG) return (REGNO (x) == REGNO (y) && (! rtx_equal_function_value_matters || REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y))); if (code == LABEL_REF) return XEXP (x, 0) == XEXP (y, 0); if (code == SYMBOL_REF)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -