📄 reload.c
字号:
register char *fmt; int success_2; if (x == y) return 1; if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)) && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG && GET_CODE (SUBREG_REG (y)) == REG))) { register int j; if (code == SUBREG) { i = REGNO (SUBREG_REG (x)); if (i >= FIRST_PSEUDO_REGISTER) goto slow; i += SUBREG_WORD (x); } else i = REGNO (x); if (GET_CODE (y) == SUBREG) { j = REGNO (SUBREG_REG (y)); if (j >= FIRST_PSEUDO_REGISTER) goto slow; j += SUBREG_WORD (y); } else j = REGNO (y); return i == j; } /* If two operands must match, because they are really a single operand of an assembler insn, then two postincrements are invalid because the assembler insn would increment only once. On the other hand, an postincrement matches ordinary indexing if the postincrement is the output operand. */ if (code == POST_DEC || code == POST_INC) return operands_match_p (XEXP (x, 0), y); /* Two preincrements are invalid because the assembler insn would increment only once. On the other hand, an preincrement matches ordinary indexing if the preincrement is the input operand. In this case, return 2, since some callers need to do special things when this happens. */ if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC) return operands_match_p (x, XEXP (y, 0)) ? 2 : 0; slow: /* Now we have disposed of all the cases in which different rtx codes can match. */ if (code != GET_CODE (y)) return 0; if (code == LABEL_REF) return XEXP (x, 0) == XEXP (y, 0); if (code == SYMBOL_REF) return XSTR (x, 0) == XSTR (y, 0); /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ if (GET_MODE (x) != GET_MODE (y)) return 0; /* Compare the elements. If any pair of corresponding elements fail to match, return 0 for the whole things. */ success_2 = 0; fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { int val; switch (fmt[i]) { case 'i': if (XINT (x, i) != XINT (y, i)) return 0; break; case 'e': val = operands_match_p (XEXP (x, i), XEXP (y, i)); if (val == 0) return 0; /* If any subexpression returns 2, we should return 2 if we are successful. */ if (val == 2) success_2 = 1; 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 + success_2;}/* Return the number of times character C occurs in string S. */static intn_occurrences (c, s) char c; char *s;{ int n = 0; while (*s) n += (*s++ == c); return n;}struct decomposition{ int reg_flag; int safe; rtx base; int start; int end;};/* Describe the range of registers or memory referenced by X. If X is a register, set REG_FLAG and put the first register number into START and the last plus one into END. If X is a memory reference, put a base address into BASE and a range of integer offsets into START and END. If X is pushing on the stack, we can assume it causes no trouble, so we set the SAFE field. */static struct decompositiondecompose (x) rtx x;{ struct decomposition val; int all_const = 0; val.reg_flag = 0; val.safe = 0; if (GET_CODE (x) == MEM) { rtx base, offset = 0; rtx addr = XEXP (x, 0); if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) { val.base = XEXP (addr, 0); val.start = - GET_MODE_SIZE (GET_MODE (x)); val.end = GET_MODE_SIZE (GET_MODE (x)); val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; return val; } if (GET_CODE (addr) == CONST) { addr = XEXP (addr, 0); all_const = 1; } if (GET_CODE (addr) == PLUS) { if (CONSTANT_P (XEXP (addr, 0))) { base = XEXP (addr, 1); offset = XEXP (addr, 0); } else if (CONSTANT_P (XEXP (addr, 1))) { base = XEXP (addr, 0); offset = XEXP (addr, 1); } } if (offset == 0) { base = addr; offset = const0_rtx; } if (GET_CODE (offset) == CONST) offset = XEXP (offset, 0); if (GET_CODE (offset) == PLUS) { if (GET_CODE (XEXP (offset, 0)) == CONST_INT) { base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 1)); offset = XEXP (offset, 0); } else if (GET_CODE (XEXP (offset, 1)) == CONST_INT) { base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 0)); offset = XEXP (offset, 1); } else { base = gen_rtx (PLUS, GET_MODE (base), base, offset); offset = const0_rtx; } } else if (GET_CODE (offset) != CONST_INT) { base = gen_rtx (PLUS, GET_MODE (base), base, offset); offset = const0_rtx; } if (all_const && GET_CODE (base) == PLUS) base = gen_rtx (CONST, GET_MODE (base), base); if (GET_CODE (offset) != CONST_INT) abort (); val.start = INTVAL (offset); val.end = val.start + GET_MODE_SIZE (GET_MODE (x)); val.base = base; return val; } else if (GET_CODE (x) == REG) { val.reg_flag = 1; val.start = true_regnum (x); if (val.start < 0) { /* A pseudo with no hard reg. */ val.start = REGNO (x); val.end = val.start + 1; } else /* A hard reg. */ val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x)); } else if (GET_CODE (x) == SUBREG) { if (GET_CODE (SUBREG_REG (x)) != REG) /* This could be more precise, but it's good enough. */ return decompose (SUBREG_REG (x)); val.reg_flag = 1; val.start = true_regnum (x); if (val.start < 0) return decompose (SUBREG_REG (x)); else /* A hard reg. */ val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x)); } else abort (); return val;}/* Return 1 if altering Y will not modify the value of X. Y is also described by YDATA, which should be decompose (Y). */static intimmune_p (x, y, ydata) rtx x, y; struct decomposition ydata;{ struct decomposition xdata; if (ydata.reg_flag) return !refers_to_regno_p (ydata.start, ydata.end, x, 0); if (ydata.safe) return 1; if (GET_CODE (y) != MEM) abort (); /* If Y is memory and X is not, Y can't affect X. */ if (GET_CODE (x) != MEM) return 1; xdata = decompose (x); if (! rtx_equal_p (xdata.base, ydata.base)) { /* If bases are distinct symbolic constants, there is no overlap. */ if (CONSTANT_P (xdata.base) && CONSTANT_P (ydata.base)) return 1; /* Constants and stack slots never overlap. */ if (CONSTANT_P (xdata.base) && (ydata.base == frame_pointer_rtx || ydata.base == stack_pointer_rtx)) return 1; if (CONSTANT_P (ydata.base) && (xdata.base == frame_pointer_rtx || xdata.base == stack_pointer_rtx)) return 1; /* If either base is variable, we don't know anything. */ return 0; } return (xdata.start >= ydata.end || ydata.start >= xdata.end);}/* Main entry point of this file: search the body of INSN for values that need reloading and record them with push_reload. REPLACE nonzero means record also where the values occur so that subst_reloads can be used. IND_OK says that a memory reference is a valid memory address. LIVE_KNOWN says we have valid information about which hard regs are live at each point in the program; this is true when we are called from global_alloc but false when stupid register allocation has been done. RELOAD_REG_P if nonzero is a vector indexed by hard reg number which is nonnegative if the reg has been commandeered for reloading into. It is copied into STATIC_RELOAD_REG_P and referenced from there by various subroutines. */voidfind_reloads (insn, replace, ind_ok, live_known, reload_reg_p) rtx insn; int replace, ind_ok; int live_known; short *reload_reg_p;{#ifdef REGISTER_CONSTRAINTS enum reload_modified { RELOAD_NOTHING, RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE }; register int insn_code_number; register int i; int noperands; /* These are the constraints for the insn. We don't change them. */ char *constraints1[MAX_RECOG_OPERANDS]; /* These start out as the constraints for the insn and they are chewed up as we consider alternatives. */ char *constraints[MAX_RECOG_OPERANDS]; /* Nonzero for a MEM operand whose entire address needs a reload. */ int address_reloaded[MAX_RECOG_OPERANDS]; int n_alternatives; int this_alternative[MAX_RECOG_OPERANDS]; char this_alternative_win[MAX_RECOG_OPERANDS]; char this_alternative_offmemok[MAX_RECOG_OPERANDS]; char this_alternative_earlyclobber[MAX_RECOG_OPERANDS]; int this_alternative_matches[MAX_RECOG_OPERANDS]; int swapped; int goal_alternative[MAX_RECOG_OPERANDS]; int this_alternative_number; int goal_alternative_number; int operand_reloadnum[MAX_RECOG_OPERANDS]; int goal_alternative_matches[MAX_RECOG_OPERANDS]; int goal_alternative_matched[MAX_RECOG_OPERANDS]; char goal_alternative_win[MAX_RECOG_OPERANDS]; char goal_alternative_offmemok[MAX_RECOG_OPERANDS]; char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS]; int goal_alternative_swapped; enum reload_modified modified[MAX_RECOG_OPERANDS]; int best; int commutative; char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS]; rtx substed_operand[MAX_RECOG_OPERANDS]; rtx body = PATTERN (insn); int goal_earlyclobber, this_earlyclobber; enum machine_mode operand_mode[MAX_RECOG_OPERANDS]; this_insn = insn; this_insn_is_asm = 0; /* Tentative. */ n_reloads = 0; n_replacements = 0; n_memlocs = 0; n_earlyclobbers = 0; replace_reloads = replace; indirect_ok = ind_ok; hard_regs_live_known = live_known; static_reload_reg_p = reload_reg_p; /* Find what kind of insn this is. NOPERANDS gets number of operands. Make OPERANDS point to a vector of operand values. Make OPERAND_LOCS point to a vector of pointers to where the operands were found. Fill CONSTRAINTS and CONSTRAINTS1 with pointers to the constraint-strings for this insn. Return if the insn needs no reload processing. */ switch (GET_CODE (body)) { case USE: case CLOBBER: case ASM_INPUT: case ADDR_VEC: case ADDR_DIFF_VEC: return; case SET: /* Dispose quickly of (set (reg..) (reg..)) if both have hard regs. */ if (GET_CODE (SET_DEST (body)) == REG && REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER && GET_CODE (SET_SRC (body)) == REG && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER) return; case PARALLEL: case ASM_OPERANDS: noperands = asm_noperands (body); if (noperands >= 0) { /* This insn is an `asm' with operands. */ insn_code_number = -1; this_insn_is_asm = 1; /* expand_asm_operands makes sure there aren't too many operands. */ if (noperands > MAX_RECOG_OPERANDS) abort ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -