📄 reload.c
字号:
/* Search an insn for pseudo regs that must be in hard regs and are not. Copyright (C) 1987, 1988, 1989, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. *//* This file contains subroutines used only from the file reload1.c. It knows how to scan one insn for operands and values that need to be copied into registers to make valid code. It also finds other operands and values which are valid but for which equivalent values in registers exist and ought to be used instead. Before processing the first insn of the function, call `init_reload'. To scan an insn, call `find_reloads'. This does two things: 1. sets up tables describing which values must be reloaded for this insn, and what kind of hard regs they must be reloaded into; 2. optionally record the locations where those values appear in the data, so they can be replaced properly later. This is done only if the second arg to `find_reloads' is nonzero. The third arg to `find_reloads' specifies the number of levels of indirect addressing supported by the machine. If it is zero, indirect addressing is not valid. If it is one, (MEM (REG n)) is valid even if (REG n) did not get a hard register; if it is two, (MEM (MEM (REG n))) is also valid even if (REG n) did not get a hard register, and similarly for higher values. Then you must choose the hard regs to reload those pseudo regs into, and generate appropriate load insns before this insn and perhaps also store insns after this insn. Set up the array `reload_reg_rtx' to contain the REG rtx's for the registers you used. In some cases `find_reloads' will return a nonzero value in `reload_reg_rtx' for certain reloads. Then that tells you which register to use, so you do not need to allocate one. But you still do need to add extra instructions to copy the value into and out of that register. Finally you must call `subst_reloads' to substitute the reload reg rtx's into the locations already recorded.NOTE SIDE EFFECTS: find_reloads can alter the operands of the instruction it is called on. 1. Two operands of any sort may be interchanged, if they are in a commutative instruction. This happens only if find_reloads thinks the instruction will compile better that way. 2. Pseudo-registers that are equivalent to constants are replaced with those constants if they are not in hard registers.1 happens every time find_reloads is called.2 happens only when REPLACE is 1, which is only whenactually doing the reloads, not when just counting them.Using a reload register for several reloads in one insn:When an insn has reloads, it is considered as having three parts:the input reloads, the insn itself after reloading, and the output reloads.Reloads of values used in memory addresses are often needed for only one part.When this is so, reload_when_needed records which part needs the reload.Two reloads for different parts of the insn can share the same reloadregister.When a reload is used for addresses in multiple parts, or when it isan ordinary operand, it is classified as RELOAD_OTHER, and cannot sharea register with any other reload. */#define REG_OK_STRICT#include "config.h"#include "rtl.h"#include "insn-config.h"#include "insn-codes.h"#include "recog.h"#include "reload.h"#include "regs.h"#include "hard-reg-set.h"#include "flags.h"#include "real.h"#ifndef REGISTER_MOVE_COST#define REGISTER_MOVE_COST(x, y) 2#endif/* The variables set up by `find_reloads' are: n_reloads number of distinct reloads needed; max reload # + 1 tables indexed by reload number reload_in rtx for value to reload from reload_out rtx for where to store reload-reg afterward if nec (often the same as reload_in) reload_reg_class enum reg_class, saying what regs to reload into reload_inmode enum machine_mode; mode this operand should have when reloaded, on input. reload_outmode enum machine_mode; mode this operand should have when reloaded, on output. reload_strict_low char; currently always zero; used to mean that this reload is inside a STRICT_LOW_PART, but we don't need to know this anymore. reload_optional char, nonzero for an optional reload. Optional reloads are ignored unless the value is already sitting in a register. reload_inc int, positive amount to increment or decrement by if reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC. Ignored otherwise (don't assume it is zero). reload_in_reg rtx. A reg for which reload_in is the equivalent. If reload_in is a symbol_ref which came from reg_equiv_constant, then this is the pseudo which has that symbol_ref as equivalent. reload_reg_rtx rtx. This is the register to reload into. If it is zero when `find_reloads' returns, you must find a suitable register in the class specified by reload_reg_class, and store here an rtx for that register with mode from reload_inmode or reload_outmode. reload_nocombine char, nonzero if this reload shouldn't be combined with another reload. reload_needed_for rtx, operand this reload is needed for address of. 0 means it isn't needed for addressing. reload_needed_for_multiple int, 1 if this reload needed for more than one thing. reload_when_needed enum, classifies reload as needed either for addressing an input reload, addressing an output, for addressing a non-reloaded mem ref, or for unspecified purposes (i.e., more than one of the above). reload_secondary_reload int, gives the reload number of a secondary reload, when needed; otherwise -1 reload_secondary_p int, 1 if this is a secondary register for one or more reloads. reload_secondary_icode enum insn_code, if a secondary reload is required, gives the INSN_CODE that uses the secondary reload as a scratch register, or CODE_FOR_nothing if the secondary reload register is to be an intermediate register. */int n_reloads;rtx reload_in[MAX_RELOADS];rtx reload_out[MAX_RELOADS];enum reg_class reload_reg_class[MAX_RELOADS];enum machine_mode reload_inmode[MAX_RELOADS];enum machine_mode reload_outmode[MAX_RELOADS];char reload_strict_low[MAX_RELOADS];rtx reload_reg_rtx[MAX_RELOADS];char reload_optional[MAX_RELOADS];int reload_inc[MAX_RELOADS];rtx reload_in_reg[MAX_RELOADS];char reload_nocombine[MAX_RELOADS];int reload_needed_for_multiple[MAX_RELOADS];rtx reload_needed_for[MAX_RELOADS];enum reload_when_needed reload_when_needed[MAX_RELOADS];int reload_secondary_reload[MAX_RELOADS];int reload_secondary_p[MAX_RELOADS];enum insn_code reload_secondary_icode[MAX_RELOADS];/* All the "earlyclobber" operands of the current insn are recorded here. */int n_earlyclobbers;rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];/* Replacing reloads. If `replace_reloads' is nonzero, then as each reload is recorded an entry is made for it in the table `replacements'. Then later `subst_reloads' can look through that table and perform all the replacements needed. *//* Nonzero means record the places to replace. */static int replace_reloads;/* Each replacement is recorded with a structure like this. */struct replacement{ rtx *where; /* Location to store in */ rtx *subreg_loc; /* Location of SUBREG if WHERE is inside a SUBREG; 0 otherwise. */ int what; /* which reload this is for */ enum machine_mode mode; /* mode it must have */};static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];/* Number of replacements currently recorded. */static int n_replacements;/* MEM-rtx's created for pseudo-regs in stack slots not directly addressable; (see reg_equiv_address). */static rtx memlocs[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];static int n_memlocs;#ifdef SECONDARY_MEMORY_NEEDED/* Save MEMs needed to copy from one class of registers to another. One MEM is used per mode, but normally only one or two modes are ever used. We keep two versions, before and after register elimination. */static rtx secondary_memlocs[NUM_MACHINE_MODES];static rtx secondary_memlocs_elim[NUM_MACHINE_MODES];#endif/* The instruction we are doing reloads for; so we can test whether a register dies in it. */static rtx this_insn;/* Nonzero if this instruction is a user-specified asm with operands. */static int this_insn_is_asm;/* If hard_regs_live_known is nonzero, we can tell which hard regs are currently live, at least enough to succeed in choosing dummy reloads. */static int hard_regs_live_known;/* Indexed by hard reg number, element is nonegative if hard reg has been spilled. This vector is passed to `find_reloads' as an argument and is not changed here. */static short *static_reload_reg_p;/* Set to 1 in subst_reg_equivs if it changes anything. */static int subst_reg_equivs_changed;/* On return from push_reload, holds the reload-number for the OUT operand, which can be different for that from the input operand. */static int output_reloadnum;static int alternative_allows_memconst ();static rtx find_dummy_reload ();static rtx find_reloads_toplev ();static int find_reloads_address ();static int find_reloads_address_1 ();static void find_reloads_address_part ();static int hard_reg_set_here_p ();/* static rtx forget_volatility (); */static rtx subst_reg_equivs ();static rtx subst_indexed_address ();void copy_replacements ();rtx find_equiv_reg ();static int find_inc_amount ();#ifdef HAVE_SECONDARY_RELOADS/* Determine if any secondary reloads are needed for loading (if IN_P is non-zero) or storing (if IN_P is zero) X to or from a reload register of register class RELOAD_CLASS in mode RELOAD_MODE. Return the register class of a secondary reload register, or NO_REGS if none. *PMODE is set to the mode that the register is required in. If the reload register is needed as a scratch register instead of an intermediate register, *PICODE is set to the insn_code of the insn to be used to load or store the primary reload register; otherwise *PICODE is set to CODE_FOR_nothing. In some cases (such as storing MQ into an external memory location on the RT), both an intermediate register and a scratch register. In that case, *PICODE is set to CODE_FOR_nothing, the class for the intermediate register is returned, and the *PTERTIARY_... variables are set to describe the scratch register. */static enum reg_classfind_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode, ptertiary_class, ptertiary_icode, ptertiary_mode) rtx x; enum reg_class reload_class; enum machine_mode reload_mode; int in_p; enum insn_code *picode; enum machine_mode *pmode; enum reg_class *ptertiary_class; enum insn_code *ptertiary_icode; enum machine_mode *ptertiary_mode;{ enum reg_class class = NO_REGS; enum machine_mode mode = reload_mode; enum insn_code icode = CODE_FOR_nothing; enum reg_class t_class = NO_REGS; enum machine_mode t_mode = VOIDmode; enum insn_code t_icode = CODE_FOR_nothing; /* If X is a pseudo-register that has an equivalent MEM (actually, if it is still a pseudo-register by now, it *must* have an equivalent MEM but we don't want to assume that), use that equivalent when seeing if a secondary reload is needed since whether or not a reload is needed might be sensitive to the form of the MEM. */ if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_equiv_mem[REGNO (x)] != 0) x = reg_equiv_mem[REGNO (x)];#ifdef SECONDARY_INPUT_RELOAD_CLASS if (in_p) class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS if (! in_p) class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);#endif /* If we don't need any secondary registers, go away; the rest of the values won't be used. */ if (class == NO_REGS) return NO_REGS; /* Get a possible insn to use. If the predicate doesn't accept X, don't use the insn. */ icode = (in_p ? reload_in_optab[(int) reload_mode] : reload_out_optab[(int) reload_mode]); if (icode != CODE_FOR_nothing && insn_operand_predicate[(int) icode][in_p] && (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode))) icode = CODE_FOR_nothing; /* If we will be using an insn, see if it can directly handle the reload register we will be using. If it can, the secondary reload is for a scratch register. If it can't, we will use the secondary reload for an intermediate register and require a tertiary reload for the scratch register. */ if (icode != CODE_FOR_nothing) { /* If IN_P is non-zero, the reload register will be the output in operand 0. If IN_P is zero, the reload register will be the input in operand 1. Outputs should have an initial "=", which we must skip. */ char insn_letter = insn_operand_constraint[(int) icode][!in_p][in_p]; enum reg_class insn_class = (insn_letter == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (insn_letter)); if (insn_class == NO_REGS || (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=') /* The scratch register's constraint must start with "=&". */ || insn_operand_constraint[(int) icode][2][0] != '=' || insn_operand_constraint[(int) icode][2][1] != '&') abort (); if (reg_class_subset_p (reload_class, insn_class)) mode = insn_operand_mode[(int) icode][2]; else { char t_letter = insn_operand_constraint[(int) icode][2][2]; class = insn_class; t_mode = insn_operand_mode[(int) icode][2]; t_class = (t_letter == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (t_letter)); t_icode = icode; icode = CODE_FOR_nothing; } } *pmode = mode; *picode = icode; *ptertiary_class = t_class; *ptertiary_mode = t_mode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -