rtlanal.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,983 行 · 第 1/4 页
C
1,983 行
}/* Similar to reg_set_between_p, but check all registers in X. Return 0 only if none of them are modified between START and END. Return 1 if X contains a MEM; this routine does not perform any memory aliasing. */intmodified_between_p (x, start, end) rtx x; rtx start, end;{ enum rtx_code code = GET_CODE (x); char *fmt; int i, j; switch (code) { case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: return 0; case PC: case CC0: return 1; case MEM: /* If the memory is not constant, assume it is modified. If it is constant, we still have to check the address. */ if (! RTX_UNCHANGING_P (x)) return 1; break; case REG: return reg_set_between_p (x, start, end); default: break; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && modified_between_p (XEXP (x, i), start, end)) return 1; if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) if (modified_between_p (XVECEXP (x, i, j), start, end)) return 1; } return 0;}/* Similar to reg_set_p, but check all registers in X. Return 0 only if none of them are modified in INSN. Return 1 if X contains a MEM; this routine does not perform any memory aliasing. */intmodified_in_p (x, insn) rtx x; rtx insn;{ enum rtx_code code = GET_CODE (x); char *fmt; int i, j; switch (code) { case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: return 0; case PC: case CC0: return 1; case MEM: /* If the memory is not constant, assume it is modified. If it is constant, we still have to check the address. */ if (! RTX_UNCHANGING_P (x)) return 1; break; case REG: return reg_set_p (x, insn); default: break; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && modified_in_p (XEXP (x, i), insn)) return 1; if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) if (modified_in_p (XVECEXP (x, i, j), insn)) return 1; } return 0;}/* Given an INSN, return a SET expression if this insn has only a single SET. It may also have CLOBBERs, USEs, or SET whose output will not be used, which we ignore. */rtxsingle_set (insn) rtx insn;{ rtx set; int i; if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') return 0; if (GET_CODE (PATTERN (insn)) == SET) return PATTERN (insn); else if (GET_CODE (PATTERN (insn)) == PARALLEL) { for (i = 0, set = 0; i < XVECLEN (PATTERN (insn), 0); i++) if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET && (! find_reg_note (insn, REG_UNUSED, SET_DEST (XVECEXP (PATTERN (insn), 0, i))) || side_effects_p (XVECEXP (PATTERN (insn), 0, i)))) { if (set) return 0; else set = XVECEXP (PATTERN (insn), 0, i); } return set; } return 0;}/* Return the last thing that X was assigned from before *PINSN. Verify that the object is not modified up to VALID_TO. If it was, if we hit a partial assignment to X, or hit a CODE_LABEL first, return X. If we found an assignment, update *PINSN to point to it. */rtxfind_last_value (x, pinsn, valid_to) rtx x; rtx *pinsn; rtx valid_to;{ rtx p; for (p = PREV_INSN (*pinsn); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p)) if (GET_RTX_CLASS (GET_CODE (p)) == 'i') { rtx set = single_set (p); rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX); if (set && rtx_equal_p (x, SET_DEST (set))) { rtx src = SET_SRC (set); if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST) src = XEXP (note, 0); if (! modified_between_p (src, PREV_INSN (p), valid_to) /* Reject hard registers because we don't usually want to use them; we'd rather use a pseudo. */ && ! (GET_CODE (src) == REG && REGNO (src) < FIRST_PSEUDO_REGISTER)) { *pinsn = p; return src; } } /* If set in non-simple way, we don't have a value. */ if (reg_set_p (x, p)) break; } return x;} /* Return nonzero if 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: /* The contents of a REG_NONNEG note is always zero, so we must come here upon repeat in case the last REG_NOTE is a REG_NONNEG note. */ if (x == 0) return 0; code = GET_CODE (x); switch (code) { case REG: i = REGNO (x); /* If we modifying the stack, frame, or argument pointer, it will clobber a virtual register. In fact, we could be more precise, but it isn't worth it. */ if ((i == STACK_POINTER_REGNUM#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM || i == ARG_POINTER_REGNUM#endif || i == FRAME_POINTER_REGNUM) && regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER) return 1; return (endregno > i && regno < i + (i < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (i, GET_MODE (x)) : 1)); case SUBREG: /* If this is a SUBREG of a hard reg, we can see exactly which registers are being modified. Otherwise, handle normally. */ if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); return endregno > inner_regno && regno < inner_endregno; } break; case CLOBBER: case SET: if (&SET_DEST (x) != loc /* Note setting a SUBREG counts as referring to the REG it is in for a pseudo but not for hard registers since we can treat each word individually. */ && ((GET_CODE (SET_DEST (x)) == SUBREG && loc != &SUBREG_REG (SET_DEST (x)) && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG && REGNO (SUBREG_REG (SET_DEST (x))) >= FIRST_PSEUDO_REGISTER && refers_to_regno_p (regno, endregno, SUBREG_REG (SET_DEST (x)), loc)) || (GET_CODE (SET_DEST (x)) != REG && refers_to_regno_p (regno, endregno, SET_DEST (x), loc)))) return 1; if (code == CLOBBER || loc == &SET_SRC (x)) return 0; x = SET_SRC (x); goto repeat; default: break; } /* 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 modifying X will affect IN. If X is a register or a SUBREG, we check if any register number in X conflicts with the relevant register numbers. If X is a constant, return 0. If X is a MEM, return 1 iff IN contains a MEM (we don't bother checking for memory addresses that can't conflict because we expect this to be a rare case. */intreg_overlap_mentioned_p (x, in) rtx x, in;{ int regno, endregno; if (GET_CODE (x) == SUBREG) { regno = REGNO (SUBREG_REG (x)); if (regno < FIRST_PSEUDO_REGISTER) regno += SUBREG_WORD (x); } else if (GET_CODE (x) == REG) regno = REGNO (x); else if (CONSTANT_P (x)) return 0; else if (GET_CODE (x) == MEM) { char *fmt; int i; if (GET_CODE (in) == MEM) return 1; fmt = GET_RTX_FORMAT (GET_CODE (in)); for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--) if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i))) return 1; return 0; } else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC || GET_CODE (x) == CC0) return reg_mentioned_p (x, in); else abort (); endregno = regno + (regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); return refers_to_regno_p (regno, endregno, in, NULL_PTR);}/* Used for communications between the next few functions. */static int reg_set_last_unknown;static rtx reg_set_last_value;static int reg_set_last_first_regno, reg_set_last_last_regno;/* Called via note_stores from reg_set_last. */static voidreg_set_last_1 (x, pat) rtx x; rtx pat;{ int first, last; /* If X is not a register, or is not one in the range we care about, ignore. */ if (GET_CODE (x) != REG) return; first = REGNO (x); last = first + (first < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (first, GET_MODE (x)) : 1); if (first >= reg_set_last_last_regno || last <= reg_set_last_first_regno) return; /* If this is a CLOBBER or is some complex LHS, or doesn't modify exactly the registers we care about, show we don't know the value. */ if (GET_CODE (pat) == CLOBBER || SET_DEST (pat) != x || first != reg_set_last_first_regno || last != reg_set_last_last_regno) reg_set_last_unknown = 1; else reg_set_last_value = SET_SRC (pat);}/* Return the last value to which REG was set prior to INSN. If we can't find it easily, return 0. We only return a REG, SUBREG, or constant because it is too hard to check if a MEM remains unchanged. */rtxreg_set_last (x, insn) rtx x; rtx insn;{ rtx orig_insn = insn; reg_set_last_first_regno = REGNO (x); reg_set_last_last_regno = reg_set_last_first_regno + (reg_set_last_first_regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (reg_set_last_first_regno, GET_MODE (x)) : 1); reg_set_last_unknown = 0; reg_set_last_value = 0; /* Scan backwards until reg_set_last_1 changed one of the above flags. Stop when we reach a label or X is a hard reg and we reach a CALL_INSN (if reg_set_last_last_regno is a hard reg). If we find a set of X, ensure that its SET_SRC remains unchanged. */ /* We compare with <= here, because reg_set_last_last_regno is actually the number of the first reg *not* in X. */ for (; insn && GET_CODE (insn) != CODE_LABEL && ! (GET_CODE (insn) == CALL_INSN && reg_set_last_last_regno <= FIRST_PSEUDO_REGISTER); insn = PREV_INSN (insn)) if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') { note_stores (PATTERN (insn), reg_set_last_1); if (reg_set_last_unknown) return 0; else if (reg_set_last_value) { if (CONSTANT_P (reg_set_last_value) || ((GET_CODE (reg_set_last_value) == REG || GET_CODE (reg_set_last_value) == SUBREG) && ! reg_set_between_p (reg_set_last_value, insn, orig_insn))) return reg_set_last_value; else return 0; } } return 0;}/* This is 1 until after the rtl generation 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; /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively. */ if (code == REG) /* Until rtl generation is complete, don't consider 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 is no longer needed, they can be considered equivalent. */ return (REGNO (x) == REGNO (y) && (! rtx_equal_function_value_matters || REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y))); else if (code == LABEL_REF) return XEXP (x, 0) == XEXP (y, 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?