📄 reload1.c
字号:
#ifdef SMALL_REGISTER_CLASSES CLEAR_HARD_REG_SET (forbidden_regs);#else COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);#endif /* Spill any hard regs that we know we can't eliminate. */ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (! ep->can_eliminate) { spill_hard_reg (ep->from, global, dumpfile, 1); regs_ever_live[ep->from] = 1; } if (global) for (i = 0; i < N_REG_CLASSES; i++) { basic_block_needs[i] = (char *)alloca (n_basic_blocks); bzero (basic_block_needs[i], n_basic_blocks); } /* From now on, we need to emit any moves without making new pseudos. */ reload_in_progress = 1; /* This loop scans the entire function each go-round and repeats until one repetition spills no additional hard regs. */ /* This flag is set when a pseudo reg is spilled, to require another pass. Note that getting an additional reload reg does not necessarily imply any pseudo reg was spilled; sometimes we find a reload reg that no pseudo reg was allocated in. */ something_changed = 1; /* This flag is set if there are any insns that require reloading. */ something_needs_reloads = 0; /* This flag is set if there are any insns that require register eliminations. */ something_needs_elimination = 0; while (something_changed) { rtx after_call = 0; /* For each class, number of reload regs needed in that class. This is the maximum over all insns of the needs in that class of the individual insn. */ int max_needs[N_REG_CLASSES]; /* For each class, size of group of consecutive regs that is needed for the reloads of this class. */ int group_size[N_REG_CLASSES]; /* For each class, max number of consecutive groups needed. (Each group contains group_size[CLASS] consecutive registers.) */ int max_groups[N_REG_CLASSES]; /* For each class, max number needed of regs that don't belong to any of the groups. */ int max_nongroups[N_REG_CLASSES]; /* For each class, the machine mode which requires consecutive groups of regs of that class. If two different modes ever require groups of one class, they must be the same size and equally restrictive for that class, otherwise we can't handle the complexity. */ enum machine_mode group_mode[N_REG_CLASSES]; /* Record the insn where each maximum need is first found. */ rtx max_needs_insn[N_REG_CLASSES]; rtx max_groups_insn[N_REG_CLASSES]; rtx max_nongroups_insn[N_REG_CLASSES]; rtx x; int starting_frame_size = get_frame_size (); static char *reg_class_names[] = REG_CLASS_NAMES; something_changed = 0; bzero (max_needs, sizeof max_needs); bzero (max_groups, sizeof max_groups); bzero (max_nongroups, sizeof max_nongroups); bzero (max_needs_insn, sizeof max_needs_insn); bzero (max_groups_insn, sizeof max_groups_insn); bzero (max_nongroups_insn, sizeof max_nongroups_insn); bzero (group_size, sizeof group_size); for (i = 0; i < N_REG_CLASSES; i++) group_mode[i] = VOIDmode; /* Keep track of which basic blocks are needing the reloads. */ this_block = 0; /* Remember whether any element of basic_block_needs changes from 0 to 1 in this pass. */ new_basic_block_needs = 0; /* Reset all offsets on eliminable registers to their initial values. */#ifdef ELIMINABLE_REGS for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) { INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, ep->initial_offset); ep->previous_offset = ep->offset = ep->max_offset = ep->initial_offset; }#else#ifdef INITIAL_FRAME_POINTER_OFFSET INITIAL_FRAME_POINTER_OFFSET (reg_eliminate[0].initial_offset);#else if (!FRAME_POINTER_REQUIRED) abort (); reg_eliminate[0].initial_offset = 0;#endif reg_eliminate[0].previous_offset = reg_eliminate[0].max_offset = reg_eliminate[0].offset = reg_eliminate[0].initial_offset;#endif num_not_at_initial_offset = 0; bzero (&offsets_known_at[get_first_label_num ()], num_labels); /* Set a known offset for each forced label to be at the initial offset of each elimination. We do this because we assume that all computed jumps occur from a location where each elimination is at its initial offset. */ for (x = forced_labels; x; x = XEXP (x, 1)) if (XEXP (x, 0)) set_label_offsets (XEXP (x, 0), NULL_RTX, 1); /* For each pseudo register that has an equivalent location defined, try to eliminate any eliminable registers (such as the frame pointer) assuming initial offsets for the replacement register, which is the normal case. If the resulting location is directly addressable, substitute the MEM we just got directly for the old REG. If it is not addressable but is a constant or the sum of a hard reg and constant, it is probably not addressable because the constant is out of range, in that case record the address; we will generate hairy code to compute the address in a register each time it is needed. If the location is not addressable, but does not have one of the above forms, assign a stack slot. We have to do this to avoid the potential of producing lots of reloads if, e.g., a location involves a pseudo that didn't get a hard register and has an equivalent memory location that also involves a pseudo that didn't get a hard register. Perhaps at some point we will improve reload_when_needed handling so this problem goes away. But that's very hairy. */ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i]) { rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX); if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]), XEXP (x, 0))) reg_equiv_mem[i] = x, reg_equiv_address[i] = 0; else if (CONSTANT_P (XEXP (x, 0)) || (GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG && (REGNO (XEXP (XEXP (x, 0), 0)) < FIRST_PSEUDO_REGISTER) && CONSTANT_P (XEXP (XEXP (x, 0), 1)))) reg_equiv_address[i] = XEXP (x, 0), reg_equiv_mem[i] = 0; else { /* Make a new stack slot. Then indicate that something changed so we go back and recompute offsets for eliminable registers because the allocation of memory below might change some offset. reg_equiv_{mem,address} will be set up for this pseudo on the next pass around the loop. */ reg_equiv_memory_loc[i] = 0; reg_equiv_init[i] = 0; alter_reg (i, -1); something_changed = 1; } } /* If we allocated another pseudo to the stack, redo elimination bookkeeping. */ if (something_changed) continue; /* If caller-saves needs a group, initialize the group to include the size and mode required for caller-saves. */ if (caller_save_group_size > 1) { group_mode[(int) caller_save_spill_class] = Pmode; group_size[(int) caller_save_spill_class] = caller_save_group_size; } /* Compute the most additional registers needed by any instruction. Collect information separately for each class of regs. */ for (insn = first; insn; insn = NEXT_INSN (insn)) { if (global && this_block + 1 < n_basic_blocks && insn == basic_block_head[this_block+1]) ++this_block; /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might include REG_LABEL), we need to see what effects this has on the known offsets at labels. */ if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN || (GET_RTX_CLASS (GET_CODE (insn)) == 'i' && REG_NOTES (insn) != 0)) set_label_offsets (insn, insn, 0); if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') { /* Nonzero means don't use a reload reg that overlaps the place where a function value can be returned. */ rtx avoid_return_reg = 0; rtx old_body = PATTERN (insn); int old_code = INSN_CODE (insn); rtx old_notes = REG_NOTES (insn); int did_elimination = 0; /* Initially, count RELOAD_OTHER reloads. Later, merge in the other kinds. */ int insn_needs[N_REG_CLASSES]; int insn_groups[N_REG_CLASSES]; int insn_total_groups = 0; /* Count RELOAD_FOR_INPUT_RELOAD_ADDRESS reloads. */ int insn_needs_for_inputs[N_REG_CLASSES]; int insn_groups_for_inputs[N_REG_CLASSES]; int insn_total_groups_for_inputs = 0; /* Count RELOAD_FOR_OUTPUT_RELOAD_ADDRESS reloads. */ int insn_needs_for_outputs[N_REG_CLASSES]; int insn_groups_for_outputs[N_REG_CLASSES]; int insn_total_groups_for_outputs = 0; /* Count RELOAD_FOR_OPERAND_ADDRESS reloads. */ int insn_needs_for_operands[N_REG_CLASSES]; int insn_groups_for_operands[N_REG_CLASSES]; int insn_total_groups_for_operands = 0;#if 0 /* This wouldn't work nowadays, since optimize_bit_field looks for non-strict memory addresses. */ /* Optimization: a bit-field instruction whose field happens to be a byte or halfword in memory can be changed to a move instruction. */ if (GET_CODE (PATTERN (insn)) == SET) { rtx dest = SET_DEST (PATTERN (insn)); rtx src = SET_SRC (PATTERN (insn)); if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT) optimize_bit_field (PATTERN (insn), insn, reg_equiv_mem); if (GET_CODE (src) == ZERO_EXTRACT || GET_CODE (src) == SIGN_EXTRACT) optimize_bit_field (PATTERN (insn), insn, reg_equiv_mem); }#endif /* If needed, eliminate any eliminable registers. */ if (num_eliminable) did_elimination = eliminate_regs_in_insn (insn, 0);#ifdef SMALL_REGISTER_CLASSES /* Set avoid_return_reg if this is an insn that might use the value of a function call. */ if (GET_CODE (insn) == CALL_INSN) { if (GET_CODE (PATTERN (insn)) == SET) after_call = SET_DEST (PATTERN (insn)); else if (GET_CODE (PATTERN (insn)) == PARALLEL && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); else after_call = 0; } else if (after_call != 0 && !(GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)) { if (reg_mentioned_p (after_call, PATTERN (insn))) avoid_return_reg = after_call; after_call = 0; }#endif /* SMALL_REGISTER_CLASSES */ /* Analyze the instruction. */ find_reloads (insn, 0, spill_indirect_levels, global, spill_reg_order); /* Remember for later shortcuts which insns had any reloads or register eliminations. One might think that it would be worthwhile to mark insns that need register replacements but not reloads, but this is not safe because find_reloads may do some manipulation of the insn (such as swapping commutative operands), which would be lost when we restore the old pattern after register replacement. So the actions of find_reloads must be redone in subsequent passes or in reload_as_needed. However, it is safe to mark insns that need reloads but not register replacement. */ PUT_MODE (insn, (did_elimination ? QImode : n_reloads ? HImode : VOIDmode)); /* Discard any register replacements done. */ if (did_elimination) { obstack_free (&reload_obstack, reload_firstobj); PATTERN (insn) = old_body; INSN_CODE (insn) = old_code; REG_NOTES (insn) = old_notes; something_needs_elimination = 1; } /* If this insn has no reloads, we need not do anything except in the case of a CALL_INSN when we have caller-saves and caller-save needs reloads. */ if (n_reloads == 0 && ! (GET_CODE (insn) == CALL_INSN && caller_save_spill_class != NO_REGS)) continue; something_needs_reloads = 1; for (i = 0; i < N_REG_CLASSES; i++) { insn_needs[i] = 0, insn_groups[i] = 0; insn_needs_for_inputs[i] = 0, insn_groups_for_inputs[i] = 0; insn_needs_for_outputs[i] = 0, insn_groups_for_outputs[i] = 0; insn_needs_for_operands[i] = 0, insn_groups_for_operands[i] = 0; } /* Count each reload once in every class containing the reload's own class. */ for (i = 0; i < n_reloads; i++) { register enum reg_class *p; enum reg_class class = reload_reg_class[i]; int size; enum machine_mode mode; int *this_groups; int *this_needs; int *this_total_groups; /* Don't count the dummy reloads, for which one of the regs mentioned in the insn can be used for reloading. Don't count optional reloads. Don't count reloads that got combined with others. */ if (reload_reg_rtx[i] != 0 || reload_optional[i] != 0 || (reload_out[i] == 0 && reload_in[i] == 0 && ! reload_secondary_p[i])) continue; /* Show that a reload register of this class is needed in this basic block. We do not use insn_needs and insn_groups because they are overly conservative for this purpose. */ if (global && ! basic_block_needs[(int) class][this_block]) { basic_block_needs[(int) class][this_block] = 1; new_basic_block_needs = 1; } /* Decide which time-of-use to count this reload for. */ switch (reload_when_needed[i])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -