📄 reload1.c
字号:
/* Reload pseudo regs into hard regs for insns that require hard regs. Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include <stdio.h>#include "config.h"#include "rtl.h"#include "obstack.h"#include "insn-config.h"#include "insn-flags.h"#include "insn-codes.h"#include "flags.h"#include "expr.h"#include "regs.h"#include "hard-reg-set.h"#include "reload.h"#include "recog.h"#include "basic-block.h"#include "output.h"#include "real.h"/* This file contains the reload pass of the compiler, which is run after register allocation has been done. It checks that each insn is valid (operands required to be in registers really are in registers of the proper class) and fixes up invalid ones by copying values temporarily into registers for the insns that need them. The results of register allocation are described by the vector reg_renumber; the insns still contain pseudo regs, but reg_renumber can be used to find which hard reg, if any, a pseudo reg is in. The technique we always use is to free up a few hard regs that are called ``reload regs'', and for each place where a pseudo reg must be in a hard reg, copy it temporarily into one of the reload regs. All the pseudos that were formerly allocated to the hard regs that are now in use as reload regs must be ``spilled''. This means that they go to other hard regs, or to stack slots if no other available hard regs can be found. Spilling can invalidate more insns, requiring additional need for reloads, so we must keep checking until the process stabilizes. For machines with different classes of registers, we must keep track of the register class needed for each reload, and make sure that we allocate enough reload registers of each class. The file reload.c contains the code that checks one insn for validity and reports the reloads that it needs. This file is in charge of scanning the entire rtl code, accumulating the reload needs, spilling, assigning reload registers to use for fixing up each insn, and generating the new insns to copy values into the reload registers. */#ifndef REGISTER_MOVE_COST#define REGISTER_MOVE_COST(x, y) 2#endif#ifndef MEMORY_MOVE_COST#define MEMORY_MOVE_COST(x) 4#endif/* During reload_as_needed, element N contains a REG rtx for the hard reg into which reg N has been reloaded (perhaps for a previous insn). */static rtx *reg_last_reload_reg;/* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn for an output reload that stores into reg N. */static char *reg_has_output_reload;/* Indicates which hard regs are reload-registers for an output reload in the current insn. */static HARD_REG_SET reg_is_output_reload;/* Element N is the constant value to which pseudo reg N is equivalent, or zero if pseudo reg N is not equivalent to a constant. find_reloads looks at this in order to replace pseudo reg N with the constant it stands for. */rtx *reg_equiv_constant;/* Element N is a memory location to which pseudo reg N is equivalent, prior to any register elimination (such as frame pointer to stack pointer). Depending on whether or not it is a valid address, this value is transferred to either reg_equiv_address or reg_equiv_mem. */rtx *reg_equiv_memory_loc;/* Element N is the address of stack slot to which pseudo reg N is equivalent. This is used when the address is not valid as a memory address (because its displacement is too big for the machine.) */rtx *reg_equiv_address;/* Element N is the memory slot to which pseudo reg N is equivalent, or zero if pseudo reg N is not equivalent to a memory slot. */rtx *reg_equiv_mem;/* Widest width in which each pseudo reg is referred to (via subreg). */static int *reg_max_ref_width;/* Element N is the insn that initialized reg N from its equivalent constant or memory slot. */static rtx *reg_equiv_init;/* During reload_as_needed, element N contains the last pseudo regno reloaded into the Nth reload register. This vector is in parallel with spill_regs. If that pseudo reg occupied more than one register, reg_reloaded_contents points to that pseudo for each spill register in use; all of these must remain set for an inheritance to occur. */static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER];/* During reload_as_needed, element N contains the insn for which the Nth reload register was last used. This vector is in parallel with spill_regs, and its contents are significant only when reg_reloaded_contents is significant. */static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER];/* Number of spill-regs so far; number of valid elements of spill_regs. */static int n_spills;/* In parallel with spill_regs, contains REG rtx's for those regs. Holds the last rtx used for any given reg, or 0 if it has never been used for spilling yet. This rtx is reused, provided it has the proper mode. */static rtx spill_reg_rtx[FIRST_PSEUDO_REGISTER];/* In parallel with spill_regs, contains nonzero for a spill reg that was stored after the last time it was used. The precise value is the insn generated to do the store. */static rtx spill_reg_store[FIRST_PSEUDO_REGISTER];/* This table is the inverse mapping of spill_regs: indexed by hard reg number, it contains the position of that reg in spill_regs, or -1 for something that is not in spill_regs. */static short spill_reg_order[FIRST_PSEUDO_REGISTER];/* This reg set indicates registers that may not be used for retrying global allocation. The registers that may not be used include all spill registers and the frame pointer (if we are using one). */HARD_REG_SET forbidden_regs;/* This reg set indicates registers that are not good for spill registers. They will not be used to complete groups of spill registers. This includes all fixed registers, registers that may be eliminated, and, if SMALL_REGISTER_CLASSES is not defined, registers explicitly used in the rtl. (spill_reg_order prevents these registers from being used to start a group.) */static HARD_REG_SET bad_spill_regs;/* Describes order of use of registers for reloading of spilled pseudo-registers. `spills' is the number of elements that are actually valid; new ones are added at the end. */static short spill_regs[FIRST_PSEUDO_REGISTER];/* Index of last register assigned as a spill register. We allocate in a round-robin fashion. */static int last_spill_reg;/* Describes order of preference for putting regs into spill_regs. Contains the numbers of all the hard regs, in order most preferred first. This order is different for each function. It is set up by order_regs_for_reload. Empty elements at the end contain -1. */static short potential_reload_regs[FIRST_PSEUDO_REGISTER];/* 1 for a hard register that appears explicitly in the rtl (for example, function value registers, special registers used by insns, structure value pointer registers). */static char regs_explicitly_used[FIRST_PSEUDO_REGISTER];/* Indicates if a register was counted against the need for groups. 0 means it can count against max_nongroup instead. */static HARD_REG_SET counted_for_groups;/* Indicates if a register was counted against the need for non-groups. 0 means it can become part of a new group. During choose_reload_regs, 1 here means don't use this reg as part of a group, even if it seems to be otherwise ok. */static HARD_REG_SET counted_for_nongroups;/* Indexed by pseudo reg number N, says may not delete stores into the real (memory) home of pseudo N. This is set if we already substituted a memory equivalent in some uses, which happens when we have to eliminate the fp from it. */static char *cannot_omit_stores;/* Nonzero if indirect addressing is supported on the machine; this means that spilling (REG n) does not require reloading it into a register in order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The value indicates the level of indirect addressing supported, e.g., two means that (MEM (MEM (REG n))) is also valid if (REG n) does not get a hard register. */static char spill_indirect_levels;/* Nonzero if indirect addressing is supported when the innermost MEM is of the form (MEM (SYMBOL_REF sym)). It is assumed that the level to which these are valid is the same as spill_indirect_levels, above. */char indirect_symref_ok;/* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid. */char double_reg_address_ok;/* Record the stack slot for each spilled hard register. */static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER];/* Width allocated so far for that stack slot. */static int spill_stack_slot_width[FIRST_PSEUDO_REGISTER];/* Indexed by register class and basic block number, nonzero if there is any need for a spill register of that class in that basic block. The pointer is 0 if we did stupid allocation and don't know the structure of basic blocks. */char *basic_block_needs[N_REG_CLASSES];/* First uid used by insns created by reload in this function. Used in find_equiv_reg. */int reload_first_uid;/* Flag set by local-alloc or global-alloc if anything is live in a call-clobbered reg across calls. */int caller_save_needed;/* Set to 1 while reload_as_needed is operating. Required by some machines to handle any generated moves differently. */int reload_in_progress = 0;/* These arrays record the insn_code of insns that may be needed to perform input and output reloads of special objects. They provide a place to pass a scratch register. */enum insn_code reload_in_optab[NUM_MACHINE_MODES];enum insn_code reload_out_optab[NUM_MACHINE_MODES];/* This obstack is used for allocation of rtl during register elimination. The allocated storage can be freed once find_reloads has processed the insn. */struct obstack reload_obstack;char *reload_firstobj;#define obstack_chunk_alloc xmalloc#define obstack_chunk_free free/* List of labels that must never be deleted. */extern rtx forced_labels;/* This structure is used to record information about register eliminations. Each array entry describes one possible way of eliminating a register in favor of another. If there is more than one way of eliminating a particular register, the most preferred should be specified first. */static struct elim_table{ int from; /* Register number to be eliminated. */ int to; /* Register number used as replacement. */ int initial_offset; /* Initial difference between values. */ int can_eliminate; /* Non-zero if this elimination can be done. */ int can_eliminate_previous; /* Value of CAN_ELIMINATE in previous scan over insns made by reload. */ int offset; /* Current offset between the two regs. */ int max_offset; /* Maximum offset between the two regs. */ int previous_offset; /* Offset at end of previous insn. */ int ref_outside_mem; /* "to" has been referenced outside a MEM. */ rtx from_rtx; /* REG rtx for the register to be eliminated. We cannot simply compare the number since we might then spuriously replace a hard register corresponding to a pseudo assigned to the reg to be eliminated. */ rtx to_rtx; /* REG rtx for the replacement. */} reg_eliminate[] =/* If a set of eliminable registers was specified, define the table from it. Otherwise, default to the normal case of the frame pointer being replaced by the stack pointer. */#ifdef ELIMINABLE_REGS ELIMINABLE_REGS;#else {{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}};#endif#define NUM_ELIMINABLE_REGS (sizeof reg_eliminate / sizeof reg_eliminate[0])/* Record the number of pending eliminations that have an offset not equal to their initial offset. If non-zero, we use a new copy of each replacement result in any insns encountered. */static int num_not_at_initial_offset;/* Count the number of registers that we may be able to eliminate. */static int num_eliminable;/* For each label, we record the offset of each elimination. If we reach a label by more than one path and an offset differs, we cannot do the elimination. This information is indexed by the number of the label. The first table is an array of flags that records whether we have yet encountered a label and the second table is an array of arrays, one entry in the latter array for each elimination. */static char *offsets_known_at;static int (*offsets_at)[NUM_ELIMINABLE_REGS];/* Number of labels in the current function. */static int num_labels;struct hard_reg_n_uses { int regno; int uses; };static int possible_group_p PROTO((int, int *));static void count_possible_groups PROTO((int *, enum machine_mode *, int *, int));static int modes_equiv_for_class_p PROTO((enum machine_mode, enum machine_mode, enum reg_class));static void spill_failure PROTO((rtx));static int new_spill_reg PROTO((int, int, int *, int *, int, FILE *));static void delete_dead_insn PROTO((rtx));static void alter_reg PROTO((int, int));static void mark_scratch_live PROTO((rtx));static void set_label_offsets PROTO((rtx, rtx, int));static int eliminate_regs_in_insn PROTO((rtx, int));static void mark_not_eliminable PROTO((rtx, rtx));static int spill_hard_reg PROTO((int, int, FILE *, int));static void scan_paradoxical_subregs PROTO((rtx));static int hard_reg_use_compare PROTO((struct hard_reg_n_uses *, struct hard_reg_n_uses *));static void order_regs_for_reload PROTO((void));static int compare_spill_regs PROTO((short *, short *));static void reload_as_needed PROTO((rtx, int));static void forget_old_reloads_1 PROTO((rtx, rtx));static int reload_reg_class_lower PROTO((short *, short *));static void mark_reload_reg_in_use PROTO((int, int, enum reload_type, enum machine_mode));static void clear_reload_reg_in_use PROTO((int, int, enum reload_type, enum machine_mode));static int reload_reg_free_p PROTO((int, int, enum reload_type));static int reload_reg_free_before_p PROTO((int, int, enum reload_type));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -