📄 rtlanal.c
字号:
/* 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; } /* 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 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; /* 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); else if (code == SYMBOL_REF) return XSTR (x, 0) == XSTR (y, 0); else if (code == SCRATCH || code == CONST_DOUBLE) return 0; /* Compare the elements. If any pair of corresponding elements fail to match, return 0 for the whole things. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { switch (fmt[i]) { case 'w': if (XWINT (x, i) != XWINT (y, i)) return 0; break; case 'n': case 'i': if (XINT (x, i) != XINT (y, i)) return 0; break; case 'V': case 'E': /* Two vectors must have the same length. */ if (XVECLEN (x, i) != XVECLEN (y, i)) return 0; /* And the corresponding elements must match. */ for (j = 0; j < XVECLEN (x, i); j++) if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0) return 0; break; case 'e': if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0) return 0; break; case 'S': case 's': if (strcmp (XSTR (x, i), XSTR (y, i))) return 0; break; case 'u': /* These are just backpointers, so they don't matter. */ break; case '0': break; /* It is believed that rtx's at this level will never contain anything but integers and other rtx's, except for within LABEL_REFs and SYMBOL_REFs. */ default: abort (); } } return 1;}/* Call FUN on each register or MEM that is stored into or clobbered by X. (X would be the pattern of an insn). FUN receives two arguments: the REG, MEM, CC0 or PC being stored in or clobbered, the SET or CLOBBER rtx that does the store. If the item being stored in or clobbered is a SUBREG of a hard register, the SUBREG will be passed. */ voidnote_stores (x, fun) register rtx x; void (*fun) ();{ if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)) { register rtx dest = SET_DEST (x); while ((GET_CODE (dest) == SUBREG && (GET_CODE (SUBREG_REG (dest)) != REG || REGNO (SUBREG_REG (dest)) >= FIRST_PSEUDO_REGISTER)) || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART) dest = XEXP (dest, 0); (*fun) (dest, x); } else if (GET_CODE (x) == PARALLEL) { register int i; for (i = XVECLEN (x, 0) - 1; i >= 0; i--) { register rtx y = XVECEXP (x, 0, i); if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER) { register rtx dest = SET_DEST (y); while ((GET_CODE (dest) == SUBREG && (GET_CODE (SUBREG_REG (dest)) != REG || (REGNO (SUBREG_REG (dest)) >= FIRST_PSEUDO_REGISTER))) || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART) dest = XEXP (dest, 0); (*fun) (dest, y); } } }}/* Return nonzero if X's old contents don't survive after INSN. This will be true if X is (cc0) or if X is a register and X dies in INSN or because INSN entirely sets X. "Entirely set" means set directly and not through a SUBREG, ZERO_EXTRACT or SIGN_EXTRACT, so no trace of the old contents remains. Likewise, REG_INC does not count. REG may be a hard or pseudo reg. Renumbering is not taken into account, but for this use that makes no difference, since regs don't overlap during their lifetimes. Therefore, this function may be used at any time after deaths have been computed (in flow.c). If REG is a hard reg that occupies multiple machine registers, this function will only return 1 if each of those registers will be replaced by INSN. */intdead_or_set_p (insn, x) rtx insn; rtx x;{ register int regno, last_regno; register int i; /* Can't use cc0_rtx below since this file is used by genattrtab.c. */ if (GET_CODE (x) == CC0) return 1; if (GET_CODE (x) != REG) abort (); regno = REGNO (x); last_regno = (regno >= FIRST_PSEUDO_REGISTER ? regno : regno + HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1); for (i = regno; i <= last_regno; i++) if (! dead_or_set_regno_p (insn, i)) return 0; return 1;}/* Utility function for dead_or_set_p to check an individual register. Also called from flow.c. */intdead_or_set_regno_p (insn, test_regno) rtx insn; int test_regno;{ int regno, endregno; rtx link; /* See if there is a death note for something that includes TEST_REGNO. */ for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) { if (REG_NOTE_KIND (link) != REG_DEAD || GET_CODE (XEXP (link, 0)) != REG) continue; regno = REGNO (XEXP (link, 0)); endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1 : regno + HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))); if (test_regno >= regno && test_regno < endregno) return 1; } if (GET_CODE (insn) == CALL_INSN && find_regno_fusage (insn, CLOBBER, test_regno)) return 1; if (GET_CODE (PATTERN (insn)) == SET) { rtx dest = SET_DEST (PATTERN (insn)); /* A value is totally replaced if it is the destination or the destination is a SUBREG of REGNO that does not change the number of words in it. */ if (GET_CODE (dest) == SUBREG && (((GET_MODE_SIZE (GET_MODE (dest)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))) dest = SUBREG_REG (dest); if (GET_CODE (dest) != REG) return 0; regno = REGNO (dest); endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1 : regno + HARD_REGNO_NREGS (regno, GET_MODE (dest))); return (test_regno >= regno && test_regno < endregno); } else if (GET_CODE (PATTERN (insn)) == PARALLEL) { register int i; for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) { rtx body = XVECEXP (PATTERN (insn), 0, i); if (GET_CODE (body) == SET || GET_CODE (body) == CLOBBER) { rtx dest = SET_DEST (body); if (GET_CODE (dest) == SUBREG && (((GET_MODE_SIZE (GET_MODE (dest)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))) dest = SUBREG_REG (dest); if (GET_CODE (dest) != REG) continue; regno = REGNO (dest); endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1 : regno + HARD_REGNO_NREGS (regno, GET_MODE (dest))); if (test_regno >= regno && test_regno < endregno) return 1; } } } return 0;}/* Return the reg-note of kind KIND in insn INSN, if there is one. If DATUM is nonzero, look for one whose datum is DATUM. */rtxfind_reg_note (insn, kind, datum) rtx insn; enum reg_note kind; rtx datum;{ register rtx link; for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == kind && (datum == 0 || datum == XEXP (link, 0))) return link; return 0;}/* Return the reg-note of kind KIND in insn INSN which applies to register number REGNO, if any. Return 0 if there is no such reg-note. Note that the REGNO of this NOTE need not be REGNO if REGNO is a hard register; it might be the case that the note overlaps REGNO. */rtx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -