📄 local-alloc.c
字号:
/* We don't already know about SREG, so tie it to UREG if this is the last use of UREG, provided the classes they want are compatible. */ if (find_regno_note (insn, REG_DEAD, ureg) && (reg_qty[ureg] >= FIRST_PSEUDO_REGISTER ? reg_meets_class_p (sreg, qty_min_class[reg_qty[ureg]]) : reg_meets_class_p (sreg, reg_preferred_class (ureg)))) { /* If combining these two registers would leave no satisfactory register available, don't do it. */ if (ureg >= FIRST_PSEUDO_REGISTER && sreg >= FIRST_PSEUDO_REGISTER && (qty_preferred_or_nothing[reg_qty[ureg]] || reg_preferred_or_nothing (sreg)) && ! (reg_classes_overlap_p (reg_preferred_class (ureg), reg_preferred_class (sreg), reg_n_calls_crossed[ureg] || reg_n_calls_crossed[sreg]))) return 0; if (reg_qty[ureg] == -2) reg_is_born (usedreg, insn_number); sqty = reg_qty[sreg] = reg_qty[ureg]; if (sqty < FIRST_PSEUDO_REGISTER) abort (); /* If SREG's reg class is smaller, set qty_min_class[SQTY]. */ update_qty_class (sqty, sreg); reg_offset[sreg] = reg_offset[ureg] + offset; if (sqty >= 0) { qty_n_calls_crossed[sqty] += reg_n_calls_crossed[sreg]; qty_n_refs[sqty] += reg_n_refs[sreg]; if (! reg_preferred_or_nothing (sreg)) qty_preferred_or_nothing[sqty] = 0; if (usize < ssize) { register int i; for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_qty[i] == sqty) reg_offset[i] -= offset; qty_size[sqty] = ssize; qty_mode[sqty] = GET_MODE (setreg); } } } else return 0; return 1;}/* Return 1 if the preferred class of REG allows it to be tied to a quantity or register whose class is CLASS. True if REG's reg class either contains or is contained in CLASS. */static intreg_meets_class_p (reg, class) int reg; enum reg_class class;{ register enum reg_class rclass = reg_preferred_class (reg); return (reg_class_subset_p (rclass, class) || reg_class_subset_p (class, rclass));}/* Return nonzero if R2's preferred class is the same as or contains R1's preferred class. R1 and R2 are pseudo-register numbers. */static 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 1 if the two specified classes have registers in common. If CALL_SAVED, then consider only call-saved registers. */static intreg_classes_overlap_p (c1, c2, call_saved) register enum reg_class c1; register enum reg_class c2; int call_saved;{ HARD_REG_SET c; int i; COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]); AND_HARD_REG_SET (c, reg_class_contents[(int) c2]); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (c, i) && (! call_saved || ! call_used_regs[i])) return 1; return 0;}/* Update the class of QTY assuming that REG is being tied to it. */static voidupdate_qty_class (qty, reg) int qty; int reg;{ enum reg_class rclass = reg_preferred_class (reg); if (reg_class_subset_p (rclass, qty_min_class[qty])) qty_min_class[qty] = rclass;}/* Handle something which alters the value of an rtx REG. REG is whatever is set or clobbered. (CLOBBER_FLAG says which.) If it is not really a register, we do nothing. The file-global variables `this_insn' and `this_insn_number' carry info from `block_alloc'. */static voidreg_is_set (reg, setter) rtx reg; rtx setter;{ register int regno; int clobber_flag = GET_CODE (setter) == CLOBBER; if (reg == 0 || GET_CODE (reg) != REG) return; regno = REGNO (reg); if (regno < FIRST_PSEUDO_REGISTER) { /* A hard reg is set or clobbered. Mark it as live at the moment immediately following this insn so that no pseudo can live here at that time. For a CLOBBER, mark it as live before this insn, to make sure it is free during the entire insn. */ register int lim = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); register int i; for (i = regno; i < lim; i++) { SET_HARD_REG_BIT (regs_live_at[this_insn_number], i); if (clobber_flag) SET_HARD_REG_BIT (regs_live_at[this_insn_number - 1], i); } /* If the hard reg is given a useful value and it does not die in this insn, mark it as live indefinitely afterward. */ if (! clobber_flag && ! find_regno_note (this_insn, REG_DEAD, regno)) reg_is_born (reg, this_insn_number); } else if (! clobber_flag) { /* A pseudo-reg is set (not just clobbered). */ reg_is_born (reg, this_insn_number); /* If a pseudo register dies in the same insn that sets it, say it dies in the following insn instead, because it will have to be live right after this insn. */ if (qty_death[reg_qty[regno]] == this_insn_number) { /* Calls to post_mark_life and mark_life deleted here. They only know how to handle hard regs. */ qty_death[reg_qty[regno]]++; } } else if (reg_qty[regno] >= 0 && qty_death[reg_qty[regno]] == this_insn_number && qty_birth[reg_qty[regno]] == this_insn_number) { /* A psuedo-reg is clobbered by this insn and was born and dies here. This is a temporary required for this insn and so will conflict with any other live registers at this point. We must assume that this register is used before all the inputs of the insn are dead. So this register must not conflict with any of them. Mark it as born at the previous insn. */ qty_birth[reg_qty[regno]]--; /* It should also conflict with this insn's outputs. */ qty_death[reg_qty[regno]]++; }}/* Handle beginning of the life of register REG. INSN_NUMBER is the insn at which this is happening. */static voidreg_is_born (reg, insn_number) rtx reg; int insn_number;{ register int regno = REGNO (reg); if (regno < FIRST_PSEUDO_REGISTER) mark_life (regno, GET_MODE (reg), 1); else if (reg_qty[regno] == -2) alloc_qty (regno, GET_MODE (reg), PSEUDO_REGNO_SIZE (regno), insn_number);}/* Record the death in insn DEATH_INSN_NUMBER for the register REG. */static voidwipe_dead_reg (reg, this_insn_number, death_insn_number) register rtx reg; int this_insn_number; int death_insn_number;{ register int regno = REGNO (reg); if (regno < FIRST_PSEUDO_REGISTER) { mark_life (regno, GET_MODE (reg), 0); if (this_insn_number != death_insn_number) abort ();#if 0 /* Should never get here */ post_mark_life (regno, GET_MODE (reg), 1, this_insn_number, death_insn_number);#endif } else { /* If a pseudo reg is referred to but was never set, we will find here that its qty is -2. Since these regs do not conflict with anything, mark them as born and dead in the same place. */ if (reg_qty[regno] == -2) { alloc_qty (regno, GET_MODE (reg), REG_SIZE (reg), this_insn_number); REG_NOTES (this_insn) = gen_rtx (EXPR_LIST, REG_UNSET, reg, REG_NOTES (this_insn)); } if (reg_qty[regno] >= 0) qty_death[reg_qty[regno]] = death_insn_number; }}/* Find a block of SIZE words of hard regs in reg_class CLASS that can hold something of machine-mode MODE (but actually we test only the first of the block for holding MODE) and still free between insn BORN_INSN and insn DEAD_INSN, and return the number of the first of them. Return -1 if such a block cannot be found. If QTY crosses calls, insist on a register preserved by calls, unless ACCEPT_CALL_CLOBBERED is nonzero. */static intfind_free_reg (class, mode, qty, accept_call_clobbered, born_insn, dead_insn) enum reg_class class; enum machine_mode mode; int accept_call_clobbered; int qty; int born_insn, dead_insn;{ register int i, ins;#ifdef HARD_REG_SET register /* Declare it register if it's a scalar. */#endif HARD_REG_SET used; if (accept_call_clobbered) COPY_HARD_REG_SET (used, call_fixed_reg_set); else if (qty_n_calls_crossed[qty] == 0) COPY_HARD_REG_SET (used, fixed_reg_set); else COPY_HARD_REG_SET (used, call_used_reg_set); for (ins = born_insn; ins < dead_insn; ins++) IOR_HARD_REG_SET (used, regs_live_at[ins]); IOR_COMPL_HARD_REG_SET (used, reg_class_contents[(int) class]); /* Don't use the frame pointer reg in local-alloc even if we may omit the frame pointer, because if we do that and then we need a frame pointer, reload won't know how to move the pseudo to another hard reg. It can move only regs made by global-alloc. */ SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM); /* If quantity QTY has a suggested physical register, try that one first. */ if (qty_phys_sugg[qty] >= 0) { i = qty_phys_sugg[qty]; if (! TEST_HARD_REG_BIT (used, i) && HARD_REGNO_MODE_OK (i, mode)) { register int j; register int size1 = HARD_REGNO_NREGS (i, mode); for (j = 1; j < size1 && ! TEST_HARD_REG_BIT (used, i + j); j++); if (j == size1) { post_mark_life (i, mode, 1, born_insn, dead_insn); return i; } } } /* If that doesn't find one, test each hard reg. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) {#ifdef REG_ALLOC_ORDER int regno = reg_alloc_order[i];#else int regno = i;#endif if (! TEST_HARD_REG_BIT (used, regno) && HARD_REGNO_MODE_OK (regno, mode)) { register int j; register int size1 = HARD_REGNO_NREGS (regno, mode); for (j = 1; j < size1 && ! TEST_HARD_REG_BIT (used, regno + j); j++); if (j == size1) { post_mark_life (regno, mode, 1, born_insn, dead_insn); return regno; }#ifndef REG_ALLOC_ORDER i += j; /* Skip starting points we know will lose */#endif } } /* If it would be profitable to allocate a call-clobbered register and save and restore it around calls, do that. */ if (! accept_call_clobbered && flag_caller_saves && qty_n_calls_crossed[qty] != 0 && CALLER_SAVE_PROFITABLE (qty_n_refs[qty], qty_n_calls_crossed[qty])) { i = find_free_reg (class, mode, qty, 1, born_insn, dead_insn); if (i >= 0) caller_save_needed = 1; return i; } return -1;}static voidmark_life (regno, mode, life) register int regno; enum machine_mode mode; int life;{ register int j = HARD_REGNO_NREGS (regno, mode); if (life) while (--j >= 0) SET_HARD_REG_BIT (regs_live, regno + j); else while (--j >= 0) CLEAR_HARD_REG_BIT (regs_live, regno + j);}static voidpost_mark_life (regno, mode, life, birth, death) register int regno, life, birth; enum machine_mode mode; int death;{ register int j = HARD_REGNO_NREGS (regno, mode);#ifdef HARD_REG_SET register /* Declare it register if it's a scalar. */#endif HARD_REG_SET this_reg; CLEAR_HARD_REG_SET (this_reg); while (--j >= 0) SET_HARD_REG_BIT (this_reg, regno + j); /* If a reg is born and dies in one insn, consider it live after that insn. */ if (birth == death) death++; if (life) while (birth < death) { IOR_HARD_REG_SET (regs_live_at[birth], this_reg); birth++; } else while (birth < death) { AND_COMPL_HARD_REG_SET (regs_live_at[birth], this_reg); birth++; }}voiddump_local_alloc (file) FILE *file;{ register int i; for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_renumber[i] != -1) fprintf (file, ";; Register %d in %d.\n", i, reg_renumber[i]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -