regclass.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,981 行 · 第 1/4 页
C
1,981 行
case PLUS: /* When we have an address that is a sum, we must determine whether registers are "base" or "index" regs. If there is a sum of two registers, we must choose one to be the "base". Luckily, we can use the REGNO_POINTER_FLAG to make a good choice most of the time. We only need to do this on machines that can have two registers in an address and where the base and index register classes are different. ??? This code used to set REGNO_POINTER_FLAG in some cases, but that seems bogus since it should only be set when we are sure the register is being used as a pointer. */ { rtx arg0 = XEXP (x, 0); rtx arg1 = XEXP (x, 1); register enum rtx_code code0 = GET_CODE (arg0); register enum rtx_code code1 = GET_CODE (arg1); /* Look inside subregs. */ if (code0 == SUBREG) arg0 = SUBREG_REG (arg0), code0 = GET_CODE (arg0); if (code1 == SUBREG) arg1 = SUBREG_REG (arg1), code1 = GET_CODE (arg1); /* If this machine only allows one register per address, it must be in the first operand. */ if (MAX_REGS_PER_ADDRESS == 1) record_address_regs (arg0, class, scale); /* If index and base registers are the same on this machine, just record registers in any non-constant operands. We assume here, as well as in the tests below, that all addresses are in canonical form. */ else if (INDEX_REG_CLASS == BASE_REG_CLASS) { record_address_regs (arg0, class, scale); if (! CONSTANT_P (arg1)) record_address_regs (arg1, class, scale); } /* If the second operand is a constant integer, it doesn't change what class the first operand must be. */ else if (code1 == CONST_INT || code1 == CONST_DOUBLE) record_address_regs (arg0, class, scale); /* If the second operand is a symbolic constant, the first operand must be an index register. */ else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF) record_address_regs (arg0, INDEX_REG_CLASS, scale); /* If both operands are registers but one is already a hard register of index or base class, give the other the class that the hard register is not. */ else if (code0 == REG && code1 == REG && REGNO (arg0) < FIRST_PSEUDO_REGISTER && (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0))) record_address_regs (arg1, REG_OK_FOR_BASE_P (arg0) ? INDEX_REG_CLASS : BASE_REG_CLASS, scale); else if (code0 == REG && code1 == REG && REGNO (arg1) < FIRST_PSEUDO_REGISTER && (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1))) record_address_regs (arg0, REG_OK_FOR_BASE_P (arg1) ? INDEX_REG_CLASS : BASE_REG_CLASS, scale); /* If one operand is known to be a pointer, it must be the base with the other operand the index. Likewise if the other operand is a MULT. */ else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0))) || code1 == MULT) { record_address_regs (arg0, BASE_REG_CLASS, scale); record_address_regs (arg1, INDEX_REG_CLASS, scale); } else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1))) || code0 == MULT) { record_address_regs (arg0, INDEX_REG_CLASS, scale); record_address_regs (arg1, BASE_REG_CLASS, scale); } /* Otherwise, count equal chances that each might be a base or index register. This case should be rare. */ else { record_address_regs (arg0, BASE_REG_CLASS, scale / 2); record_address_regs (arg0, INDEX_REG_CLASS, scale / 2); record_address_regs (arg1, BASE_REG_CLASS, scale / 2); record_address_regs (arg1, INDEX_REG_CLASS, scale / 2); } } break; case POST_INC: case PRE_INC: case POST_DEC: case PRE_DEC: /* Double the importance of a pseudo register that is incremented or decremented, since it would take two extra insns if it ends up in the wrong place. If the operand is a pseudo, show it is being used in an INC_DEC context. */#ifdef FORBIDDEN_INC_DEC_CLASSES if (GET_CODE (XEXP (x, 0)) == REG && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER) in_inc_dec[REGNO (XEXP (x, 0))] = 1;#endif record_address_regs (XEXP (x, 0), class, 2 * scale); break; case REG: { register struct costs *pp = &costs[REGNO (x)]; register int i; pp->mem_cost += (MEMORY_MOVE_COST (Pmode) * scale) / 2; for (i = 0; i < N_REG_CLASSES; i++) pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2; } break; default: { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') record_address_regs (XEXP (x, i), class, scale); } }}#ifdef FORBIDDEN_INC_DEC_CLASSES/* Return 1 if REG is valid as an auto-increment memory reference to an object of MODE. */static auto_inc_dec_reg_p (reg, mode) rtx reg; enum machine_mode mode;{#ifdef HAVE_POST_INCREMENT if (memory_address_p (mode, gen_rtx (POST_INC, Pmode, reg))) return 1;#endif#ifdef HAVE_POST_DECREMENT if (memory_address_p (mode, gen_rtx (POST_DEC, Pmode, reg))) return 1;#endif#ifdef HAVE_PRE_INCREMENT if (memory_address_p (mode, gen_rtx (PRE_INC, Pmode, reg))) return 1;#endif#ifdef HAVE_PRE_DECREMENT if (memory_address_p (mode, gen_rtx (PRE_DEC, Pmode, reg))) return 1;#endif return 0;}#endif#endif /* REGISTER_CONSTRAINTS *//* Allocate enough space to hold NUM_REGS registers for the tables used for reg_scan and flow_analysis that are indexed by the register number. If NEW_P is non zero, initialize all of the registers, otherwise only initialize the new registers allocated. The same table is kept from function to function, only reallocating it when we need more room. If RENUMBER_P is non zero, allocate the reg_renumber array also. */voidallocate_reg_info (num_regs, new_p, renumber_p) int num_regs; int new_p; int renumber_p;{ static int regno_allocated = 0; static int regno_max = 0; static short *renumber = (short *)0; int i; int size_info; int size_renumber; int min = (new_p) ? 0 : regno_max; /* If this message come up, and you want to fix it, then all of the tables like reg_renumber, etc. that use short will have to be found and lengthed to int or HOST_WIDE_INT. */ /* Free up all storage allocated */ if (num_regs < 0) { if (reg_n_info) { free ((char *)reg_n_info); free ((char *)renumber); reg_n_info = (reg_info *)0; renumber = (short *)0; } regno_allocated = 0; regno_max = 0; return; } if (num_regs > regno_allocated) { regno_allocated = num_regs + (num_regs / 20); /* add some slop space */ size_info = regno_allocated * sizeof (reg_info); size_renumber = regno_allocated * sizeof (short); if (!reg_n_info) { reg_n_info = (reg_info *) xmalloc (size_info); renumber = (short *) xmalloc (size_renumber); } else if (new_p) /* if we're zapping everything, no need to realloc */ { free ((char *)reg_n_info); free ((char *)renumber); reg_n_info = (reg_info *) xmalloc (size_info); renumber = (short *) xmalloc (size_renumber); } else { reg_n_info = (reg_info *) xrealloc ((char *)reg_n_info, size_info); renumber = (short *) xrealloc ((char *)renumber, size_renumber); } } if (min < num_regs) { bzero ((char *) ®_n_info[min], (num_regs - min) * sizeof (reg_info)); for (i = min; i < num_regs; i++) { REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN; renumber[i] = -1; } } if (renumber_p) reg_renumber = renumber; /* Tell the regset code about the new number of registers */ MAX_REGNO_REG_SET (num_regs, new_p, renumber_p); regno_max = num_regs;}/* This is the `regscan' pass of the compiler, run just before cse and again just before loop. It finds the first and last use of each pseudo-register and records them in the vectors regno_first_uid, regno_last_uid and counts the number of sets in the vector reg_n_sets. REPEAT is nonzero the second time this is called. *//* Maximum number of parallel sets and clobbers in any insn in this fn. Always at least 3, since the combiner could put that many together and we want this to remain correct for all the remaining passes. */int max_parallel;voidreg_scan (f, nregs, repeat) rtx f; int nregs; int repeat;{ register rtx insn; allocate_reg_info (nregs, TRUE, FALSE); max_parallel = 3; for (insn = f; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) { if (GET_CODE (PATTERN (insn)) == PARALLEL && XVECLEN (PATTERN (insn), 0) > max_parallel) max_parallel = XVECLEN (PATTERN (insn), 0); reg_scan_mark_refs (PATTERN (insn), insn, 0); if (REG_NOTES (insn)) reg_scan_mark_refs (REG_NOTES (insn), insn, 1); }}/* X is the expression to scan. INSN is the insn it appears in. NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. */static voidreg_scan_mark_refs (x, insn, note_flag) rtx x; rtx insn; int note_flag;{ register enum rtx_code code = GET_CODE (x); register rtx dest; register rtx note; switch (code) { case CONST_INT: case CONST: case CONST_DOUBLE: case CC0: case PC: case SYMBOL_REF: case LABEL_REF: case ADDR_VEC: case ADDR_DIFF_VEC: return; case REG: { register int regno = REGNO (x); REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn); if (!note_flag) REGNO_LAST_UID (regno) = INSN_UID (insn); if (REGNO_FIRST_UID (regno) == 0) REGNO_FIRST_UID (regno) = INSN_UID (insn); } break; case EXPR_LIST: if (XEXP (x, 0)) reg_scan_mark_refs (XEXP (x, 0), insn, note_flag); if (XEXP (x, 1)) reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); break; case INSN_LIST: if (XEXP (x, 1)) reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); break; case SET: /* Count a set of the destination if it is a register. */ for (dest = SET_DEST (x); GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == ZERO_EXTEND; dest = XEXP (dest, 0)) ; if (GET_CODE (dest) == REG) REG_N_SETS (REGNO (dest))++; /* If this is setting a pseudo from another pseudo or the sum of a pseudo and a constant integer and the other pseudo is known to be a pointer, set the destination to be a pointer as well. Likewise if it is setting the destination from an address or from a value equivalent to an address or to the sum of an address and something else. But don't do any of this if the pseudo corresponds to a user variable since it should have already been set as a pointer based on the type. */ if (GET_CODE (SET_DEST (x)) == REG && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER && ! REG_USERVAR_P (SET_DEST (x)) && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) && ((GET_CODE (SET_SRC (x)) == REG && REGNO_POINTER_FLAG (REGNO (SET_SRC (x)))) || ((GET_CODE (SET_SRC (x)) == PLUS || GET_CODE (SET_SRC (x)) == LO_SUM) && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT && GET_CODE (XEXP (SET_SRC (x), 0)) == REG && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (x), 0)))) || GET_CODE (SET_SRC (x)) == CONST || GET_CODE (SET_SRC (x)) == SYMBOL_REF || GET_CODE (SET_SRC (x)) == LABEL_REF || (GET_CODE (SET_SRC (x)) == HIGH && (GET_CODE (XEXP (SET_SRC (x), 0)) == CONST || GET_CODE (XEXP (SET_SRC (x), 0)) == SYMBOL_REF || GET_CODE (XEXP (SET_SRC (x), 0)) == LABEL_REF)) || ((GET_CODE (SET_SRC (x)) == PLUS || GET_CODE (SET_SRC (x)) == LO_SUM) && (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST || GET_CODE (XEXP (SET_SRC (x), 1)) == SYMBOL_REF || GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF)) || ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0 && (GET_CODE (XEXP (note, 0)) == CONST || GET_CODE (XEXP (note, 0)) == SYMBOL_REF || GET_CODE (XEXP (note, 0)) == LABEL_REF)))) REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1; /* ... fall through ... */ default: { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') reg_scan_mark_refs (XEXP (x, i), insn, note_flag); else if (fmt[i] == 'E' && XVEC (x, i) != 0) { register int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag); } } } }}/* Return nonzero if C1 is a subset of C2, i.e., if every register in C1 is also in C2. */intreg_class_subset_p (c1, c2) register enum reg_class c1; register enum reg_class c2;{ if (c1 == c2) return 1; if (c2 == ALL_REGS) win: return 1; GO_IF_HARD_REG_SUBSET (reg_class_contents[(int)c1], reg_class_contents[(int)c2], win); return 0;}/* Return nonzero if there is a register that is in both C1 and C2. */intreg_classes_intersect_p (c1, c2) register enum reg_class c1; register enum reg_class c2;{#ifdef HARD_REG_SET register#endif HARD_REG_SET c; if (c1 == c2) return 1; if (c1 == ALL_REGS || c2 == ALL_REGS) return 1; COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]); AND_HARD_REG_SET (c, reg_class_contents[(int) c2]); GO_IF_HARD_REG_SUBSET (c, reg_class_contents[(int) NO_REGS], lose); return 1; lose: return 0;}/* Release any memory allocated by register sets. */voidregset_release_memory (){ if (basic_block_live_at_start) { free_regset_vector (basic_block_live_at_start, n_basic_blocks); basic_block_live_at_start = 0; } FREE_REG_SET (regs_live_at_setjmp); bitmap_release_memory ();}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?