📄 reload1.c
字号:
n_spills++; return val;}/* Scan all insns, computing the stack depth, and convert all frame-pointer-relative references to stack-pointer-relative references. */static voideliminate_frame_pointer (first) rtx first;{ int depth = 0; int max_uid = get_max_uid (); int *label_depth = (int *) alloca ((max_uid + 1) * sizeof (int)); int i; rtx insn; for (i = 0; i <= max_uid; i++) label_depth[i] = -1; /* In this loop, for each forward branch we record the stack depth of the label it jumps to. We take advantage of the fact that the stack depth at a label reached by a backward branch is always, in GCC output, equal to the stack depth of the preceding unconditional jump, because it was either a loop statement or statement label. */ for (insn = first; insn; insn = NEXT_INSN (insn)) { rtx pattern = PATTERN (insn); switch (GET_CODE (insn)) { case INSN: frame_pointer_address_altered = 0; alter_frame_pointer_addresses (pattern, depth); /* Rerecognize insn if changed. */ if (frame_pointer_address_altered) { int old_code = INSN_CODE (insn); INSN_CODE (insn) = -1; /* It can happen that we fail to recognize the insn now because a pseudoreg inside an address got allocated to a hard reg that isn't valid for the address. When this happens, chances are it really still fits the same pattern as before. This is not a real fix for the bug, but it is safer than any real fix, and it should hold things till version 2 comes out. */ if (recog_memoized (insn) < 0) INSN_CODE (insn) = old_code; } /* Notice pushes and pops; update DEPTH. */ if (GET_CODE (pattern) == SET) {#ifdef PUSH_ROUNDING if (push_operand (SET_DEST (pattern), GET_MODE (SET_DEST (pattern)))) depth += PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (SET_DEST (pattern))));#endif if (GET_CODE (SET_DEST (pattern)) == REG && REGNO (SET_DEST (pattern)) == STACK_POINTER_REGNUM) { int delta; if (GET_CODE (SET_SRC (pattern)) == PLUS && GET_CODE (XEXP (SET_SRC (pattern), 0)) == REG && REGNO (XEXP (SET_SRC (pattern), 0)) == STACK_POINTER_REGNUM) delta = INTVAL (XEXP (SET_SRC (pattern), 1)); else if (GET_CODE (SET_SRC (pattern)) == MINUS && GET_CODE (XEXP (SET_SRC (pattern), 0)) == REG && REGNO (XEXP (SET_SRC (pattern), 0)) == STACK_POINTER_REGNUM) delta = -INTVAL (XEXP (SET_SRC (pattern), 1)); else abort ();#ifdef STACK_GROWS_DOWNWARD depth -= delta;#else depth += delta;#endif } } break; case JUMP_INSN: frame_pointer_address_altered = 0; alter_frame_pointer_addresses (pattern, depth); /* Rerecognize insn if changed. */ if (frame_pointer_address_altered) INSN_CODE (insn) = -1; if (GET_CODE (pattern) == ADDR_VEC) for (i = 0; i < XVECLEN (pattern, 0); i++) label_depth[INSN_UID (XEXP (XVECEXP (pattern, 0, i), 0))] = depth; else if (GET_CODE (pattern) == ADDR_DIFF_VEC) { label_depth[INSN_UID (XEXP (XEXP (pattern, 0), 0))] = depth; for (i = 0; i < XVECLEN (pattern, 1); i++) label_depth[INSN_UID (XEXP (XVECEXP (pattern, 1, i), 0))] = depth; } else if (JUMP_LABEL (insn)) label_depth[INSN_UID (JUMP_LABEL (insn))] = depth; else break; case CODE_LABEL: if (label_depth [INSN_UID (insn)] >= 0) depth = label_depth [INSN_UID (insn)]; break; case CALL_INSN: frame_pointer_address_altered = 0; alter_frame_pointer_addresses (pattern, depth); /* Rerecognize insn if changed. */ if (frame_pointer_address_altered) INSN_CODE (insn) = -1; break; } }}/* Walk the rtx X, converting all frame-pointer refs to stack-pointer refs on the assumption that the current temporary stack depth is DEPTH. (The size of saved registers must be added to DEPTH to get the actual offset between the logical frame-pointer and the stack pointer. FIX_FRAME_POINTER_ADDRESS takes care of that.) */static rtxalter_frame_pointer_addresses (x, depth) register rtx x; int depth;{ register int i; register char *fmt; register enum rtx_code code = GET_CODE (x); switch (code) { case CONST_INT: case CONST: case SYMBOL_REF: case LABEL_REF: case CONST_DOUBLE: case CC0: case PC: return x; case REG: /* Frame ptr can occur outside a PLUS if a stack slot can occur with offset 0. */ if (x == frame_pointer_rtx) { rtx oldx = x; FIX_FRAME_POINTER_ADDRESS (x, depth); if (x != oldx) frame_pointer_address_altered = 1; } return x; case MEM: { rtx addr = XEXP (x, 0); rtx mem; rtx old_addr = addr; FIX_FRAME_POINTER_ADDRESS (addr, depth); if (addr != old_addr) frame_pointer_address_altered = 1; /* These MEMs are normally shared. Make a changed copy; don't alter the shared MEM, since it needs to be altered differently each time it occurs (since DEPTH varies). */ mem = gen_rtx (MEM, GET_MODE (x), addr); MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (x); return mem; } case PLUS: { rtx oldx = x; /* Handle addresses being loaded or pushed, etc., rather than referenced. */ FIX_FRAME_POINTER_ADDRESS (x, depth); if (x != oldx) frame_pointer_address_altered = 1; code = GET_CODE (x); break; } } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') XEXP (x, i) = alter_frame_pointer_addresses (XEXP (x, i), depth); else if (fmt[i] == 'E') { register int j; for (j = XVECLEN (x, i) - 1; j >=0; j--) XVECEXP (x, i, j) = alter_frame_pointer_addresses (XVECEXP (x, i, j), depth); } } return x;}/* Modify the home of pseudo-reg I. The new home is present in reg_renumber[I]. FROM_REG may be the hard reg that the pseudo-reg is being spilled from; or it may be -1, meaning there is none or it is not relevant. This is used so that all pseudos spilled from a given hard reg can share one stack slot. */static voidalter_reg (i, from_reg) register int i; int from_reg;{ /* When outputting an inline function, this can happen for a reg that isn't actually used. */ if (regno_reg_rtx[i] == 0) return; /* If the reg got changed to a MEM at rtl-generation time, ignore it. */ if (GET_CODE (regno_reg_rtx[i]) != REG) return; /* Modify the reg-rtx to contain the new hard reg number or else to contain its pseudo reg number. */ REGNO (regno_reg_rtx[i]) = reg_renumber[i] >= 0 ? reg_renumber[i] : i; if (reg_renumber[i] < 0 && reg_equiv_init[i]) { /* Delete the insn that loads the pseudo register. */ PUT_CODE (reg_equiv_init[i], NOTE); NOTE_LINE_NUMBER (reg_equiv_init[i]) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (reg_equiv_init[i]) = 0; } /* If we have a pseudo that is needed but has no hard reg or equivalent, allocate a stack slot for it. */ if (reg_renumber[i] < 0 && reg_n_refs[i] > 0 && reg_equiv_constant[i] == 0 && reg_equiv_mem[i] == 0 && reg_equiv_address[i] == 0) { register rtx x, addr; int inherent_size = PSEUDO_REGNO_BYTES (i); int total_size = max (inherent_size, reg_max_ref_width[i]); /* Each pseudo reg has an inherent size which comes from its own mode, and a total size which provides room for paradoxical subregs which refer to the pseudo reg in wider modes. We can use a slot already allocated if it provides both enough inherent space and enough total space. Otherwise, we allocate a new slot, making sure that it has no less inherent space, and no less total space, then the previous slot. */ if (from_reg == -1) { /* No known place to spill from => no slot to reuse. */ x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size);#ifdef BYTES_BIG_ENDIAN /* Cancel the big-endian correction done in assign_stack_local. Get the address of the beginning of the slot. This is so we can do a big-endian correction unconditionally below. */ x = gen_rtx (MEM, GET_MODE (regno_reg_rtx[i]), plus_constant (XEXP (x, 0), inherent_size - total_size));#endif } /* Reuse a stack slot if possible. */ else if (spill_stack_slot[from_reg] != 0 && spill_stack_slot_width[from_reg] >= total_size && (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg])) >= inherent_size)) x = spill_stack_slot[from_reg]; /* Allocate a new or bigger slot. */ else { /* Compute maximum size needed, both for inherent size and for total size. */ enum machine_mode mode = GET_MODE (regno_reg_rtx[i]); if (spill_stack_slot[from_reg]) { if (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg])) > inherent_size) mode = GET_MODE (spill_stack_slot[from_reg]); if (spill_stack_slot_width[from_reg] > total_size) total_size = spill_stack_slot_width[from_reg]; } /* Make a slot with that size. */ x = assign_stack_local (mode, total_size);#ifdef BYTES_BIG_ENDIAN /* Cancel the big-endian correction done in assign_stack_local. Get the address of the beginning of the slot. This is so we can do a big-endian correction unconditionally below. */ x = gen_rtx (MEM, mode, plus_constant (XEXP (x, 0), GET_MODE_SIZE (mode) - total_size));#endif spill_stack_slot[from_reg] = x; spill_stack_slot_width[from_reg] = total_size; }#ifdef BYTES_BIG_ENDIAN /* On a big endian machine, the "address" of the slot is the address of the low part that fits its inherent mode. */ if (inherent_size < total_size) x = gen_rtx (MEM, GET_MODE (regno_reg_rtx[i]), plus_constant (XEXP (x, 0), total_size - inherent_size));#endif /* BYTES_BIG_ENDIAN */ addr = XEXP (x, 0); /* If the stack slot is directly addressable, substitute the MEM we just got directly for the old REG. Otherwise, record the address; we will generate hairy code to compute the address in a register each time it is needed. */ if (memory_address_p (GET_MODE (regno_reg_rtx[i]), addr)) reg_equiv_mem[i] = x; else reg_equiv_address[i] = XEXP (x, 0); }}/* Mark the slots in regs_ever_live for the hard regs used by pseudo-reg number REGNO. */voidmark_home_live (regno) int regno;{ register int i, lim; i = reg_renumber[regno]; if (i < 0) return; lim = i + HARD_REGNO_NREGS (i, PSEUDO_REGNO_MODE (regno)); while (i < lim) regs_ever_live[i++] = 1;}/* Kick all pseudos out of hard register REGNO. If GLOBAL is nonzero, try to find someplace else to put them. If DUMPFILE is nonzero, log actions taken on that file. Return nonzero if any pseudos needed to be kicked out or if this hard reg may appear explicitly in some instructions. */static intspill_hard_reg (regno, global, dumpfile) register int regno; int global; FILE *dumpfile;{ int something_changed = 0; register int i; /* Spill every pseudo reg that was allocated to this reg or to something that overlaps this reg. */ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_renumber[i] >= 0 && reg_renumber[i] <= regno && (reg_renumber[i] + HARD_REGNO_NREGS (reg_renumber[i], PSEUDO_REGNO_MODE (i)) > regno)) { /* If this register belongs solely to a basic block which needed no spilling, leave it be. */ if (regno != FRAME_POINTER_REGNUM && basic_block_needs && reg_basic_block[i] >= 0 && basic_block_needs[reg_basic_block[i]] == 0) continue; /* Mark it as no longer having a hard register home. */ reg_renumber[i] = -1; /* We will need to scan everything again. */ something_changed = 1; if (global) { retry_global_alloc (i, forbidden_regs); /* Update regs_ever_live for new home (if any). */ mark_home_live (i); /* If something gets spilled to the stack, we must have a frame pointer, so spill the frame pointer. */ if (reg_renumber[i] == -1 && ! frame_pointer_needed) { frame_pointer_needed = 1; forbidden_regs[FRAME_POINTER_REGNUM] = 1; spill_hard_reg (FRAME_POINTER_REGNUM, global, dumpfile); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -