reload.c as a bugzilla quip
FX Coudert
fxcoudert@gmail.com
Sun Mar 4 08:45:00 GMT 2007
Hi all,
One of the bugzilla quips (the headlines appearing at random for each
bug list) is actually the head of gcc/reload.c (full text below).
Although I understand the private joke status of these lines, it's
quite long and a quite annoying (especially on low bandwith links).
May I suggest that it is removed, or shortened to something like
"Search an insn for pseudo regs that must be in hard regs and are
not. (should be easy)"?
FX
PS: the full text of the quip is:
> /* Search an insn for pseudo regs that must be in hard regs and are
> not. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996,
> 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free
> Software Foundation, Inc. This file is part of GCC. GCC is free
> software; you can redistribute it and/or modify it under the terms
> of the GNU General Public License as published by the Free Software
> Foundation; either version 2, or (at your option) any later
> version. GCC is distributed in the hope that it will be useful, but
> WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> General Public License for more details. You should have received a
> copy of the GNU General Public License along with GCC; see the file
> COPYING. If not, write to the Free Software Foundation, 51 Franklin
> Street, Fifth Floor, Boston, MA 02110-1301, 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'. init_reload actually has
> to be called earlier anyway. 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 when actually 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 reload register. When a reload is used for
> addresses in multiple parts, or when it is an ordinary operand, it
> is classified as RELOAD_OTHER, and cannot share a register with any
> other reload. */ #define REG_OK_STRICT #include "config.h" #include
> "system.h" #include "coretypes.h" #include "tm.h" #include "rtl.h"
> #include "tm_p.h" #include "insn-config.h" #include "expr.h"
> #include "optabs.h" #include "recog.h" #include "reload.h" #include
> "regs.h" #include "addresses.h" #include "hard-reg-set.h" #include
> "flags.h" #include "real.h" #include "output.h" #include
> "function.h" #include "toplev.h" #include "params.h" #include
> "target.h" /* True if X is a constant that can be forced into the
> constant pool. */ #define CONST_POOL_OK_P(X) \ (CONSTANT_P (X) \ &&
> GET_CODE (X) != HIGH \ && !targetm.cannot_force_const_mem (X)) /*
> True if C is a non-empty register class that has too few registers
> to be safely used as a reload target class. */ #define
> SMALL_REGISTER_CLASS_P(C) \ (reg_class_size [(C)] == 1 \ ||
> (reg_class_size [(C)] >= 1 && CLASS_LIKELY_SPILLED_P (C))) /* All
> reloads of the current insn are recorded here. See reload.h for
> comments. */ int n_reloads; struct reload rld[MAX_RELOADS]; /* All
> the "earlyclobber" operands of the current insn are recorded here.
> */ int n_earlyclobbers; rtx reload_earlyclobbers
> [MAX_RECOG_OPERANDS]; int reload_n_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; /
> * Used to track what is modified by an operand. */ struct
> decomposition { int reg_flag; /* Nonzero if referencing a register.
> */ int safe; /* Nonzero if this can't conflict with anything. */
> rtx base; /* Base address for MEM. */ HOST_WIDE_INT start; /*
> Starting offset or register number. */ HOST_WIDE_INT end; /* Ending
> offset or register number. */ }; #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. The one after register elimination is record
> separately for each operand. This is done in case the address is
> not valid to be sure that we separately reload each. */ static rtx
> secondary_memlocs[NUM_MACHINE_MODES]; static rtx
> secondary_memlocs_elim[NUM_MACHINE_MODES][MAX_RECOG_OPERANDS];
> static int secondary_memlocs_elim_used = 0; #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 nonnegative 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; /* Compare two RTX's. */ #define MATCHES(x, y) \
> (x == y || (x != 0 && (REG_P (x) \ ? REG_P (y) && REGNO (x) ==
> REGNO (y) \ : rtx_equal_p (x, y) && ! side_effects_p (x)))) /*
> Indicates if two reloads purposes are for similar enough things
> that we can merge their reloads. */ #define MERGABLE_RELOADS(when1,
> when2, op1, op2) \ ((when1) == RELOAD_OTHER || (when2) ==
> RELOAD_OTHER \ || ((when1) == (when2) && (op1) == (op2)) \ ||
> ((when1) == RELOAD_FOR_INPUT && (when2) == RELOAD_FOR_INPUT) \ ||
> ((when1) == RELOAD_FOR_OPERAND_ADDRESS \ && (when2) ==
> RELOAD_FOR_OPERAND_ADDRESS) \ || ((when1) ==
> RELOAD_FOR_OTHER_ADDRESS \ && (when2) ==
> RELOAD_FOR_OTHER_ADDRESS)) /* Nonzero if these two reload purposes
> produce RELOAD_OTHER when merged. */ #define MERGE_TO_OTHER(when1,
> when2, op1, op2) \ ((when1) != (when2) \ || ! ((op1) == (op2) \ ||
> (when1) == RELOAD_FOR_INPUT \ || (when1) ==
> RELOAD_FOR_OPERAND_ADDRESS \ || (when1) ==
> RELOAD_FOR_OTHER_ADDRESS)) /* If we are going to reload an address,
> compute the reload type to use. */ #define ADDR_TYPE(type) \
> ((type) == RELOAD_FOR_INPUT_ADDRESS \ ? RELOAD_FOR_INPADDR_ADDRESS
> \ : ((type) == RELOAD_FOR_OUTPUT_ADDRESS \ ?
> RELOAD_FOR_OUTADDR_ADDRESS \ : (type))) static int
> push_secondary_reload (int, rtx, int, int, enum reg_class, enum
> machine_mode, enum reload_type, enum insn_code *,
> secondary_reload_info *); static enum reg_class find_valid_class
> (enum machine_mode, enum machine_mode, int, unsigned int); static
> int reload_inner_reg_of_subreg (rtx, enum machine_mode, int);
> static void push_replacement (rtx *, int, enum machine_mode);
> static void dup_replacements (rtx *, rtx *); static void
> combine_reloads (void); static int find_reusable_reload (rtx *,
> rtx, enum reg_class, enum reload_type, int, int); static rtx
> find_dummy_reload (rtx, rtx, rtx *, rtx *, enum machine_mode, enum
> machine_mode, enum reg_class, int, int); static int
> hard_reg_set_here_p (unsigned int, unsigned int, rtx); static
> struct decomposition decompose (rtx); static int immune_p (rtx,
> rtx, struct decomposition); static int alternative_allows_memconst
> (const char *, int); static rtx find_reloads_toplev (rtx, int, enum
> reload_type, int, int, rtx, int *); static rtx make_memloc (rtx,
> int); static int maybe_memory_address_p (enum machine_mode, rtx,
> rtx *); static int find_reloads_address (enum machine_mode, rtx *,
> rtx, rtx *, int, enum reload_type, int, rtx); static rtx
> subst_reg_equivs (rtx, rtx); static rtx subst_indexed_address
> (rtx); static void update_auto_inc_notes (rtx, int, int); static
> int find_reloads_address_1 (enum machine_mode, rtx, int, enum
> rtx_code, enum rtx_code, rtx *, int, enum reload_type,int, rtx);
> static void find_reloads_address_part (rtx, rtx *, enum reg_class,
> enum machine_mode, int, enum reload_type, int); static rtx
> find_reloads_subreg_address (rtx, int, int, enum reload_type, int,
> rtx); static void copy_replacements_1 (rtx *, rtx *, int); static
> int find_inc_amount (rtx, rtx); static int
> refers_to_mem_for_reload_p (rtx); static int
> refers_to_regno_for_reload_p (unsigned int, unsigned int, rtx, rtx
> *); /* Add NEW to reg_equiv_alt_mem_list[REGNO] if it's not present
> in the list yet. */ static void push_reg_equiv_alt_mem (int regno,
> rtx mem) { rtx it; for (it = reg_equiv_alt_mem_list [regno]; it; it
> = XEXP (it, 1)) if (rtx_equal_p (XEXP (it, 0), mem)) return;
> reg_equiv_alt_mem_list [regno] = alloc_EXPR_LIST (REG_EQUIV, mem,
> reg_equiv_alt_mem_list [regno]); } /* Determine if any secondary
> reloads are needed for loading (if IN_P is nonzero) or storing (if
> IN_P is zero) X to or from a reload register of register class
> RELOAD_CLASS in mode RELOAD_MODE. If secondary reloads are needed,
> push them. Return the reload number of the secondary reload we
> made, or -1 if we didn't need one. *PICODE is set to the insn_code
> to use if we do need a secondary reload. */ static int
> push_secondary_reload (int in_p, rtx x, int opnum, int optional,
> enum reg_class reload_class, enum machine_mode reload_mode, enum
> reload_type type, enum insn_code *picode, secondary_reload_info
> *prev_sri) { enum reg_class class = NO_REGS; enum reg_class
> scratch_class; enum machine_mode mode = reload_mode; enum insn_code
> icode = CODE_FOR_nothing; enum insn_code t_icode =
> CODE_FOR_nothing; enum reload_type secondary_type; int s_reload,
> t_reload = -1; const char *scratch_constraint; char letter;
> secondary_reload_info sri; if (type == RELOAD_FOR_INPUT_ADDRESS ||
> type == RELOAD_FOR_OUTPUT_ADDRESS || type ==
> RELOAD_FOR_INPADDR_ADDRESS || type == RELOAD_FOR_OUTADDR_ADDRESS)
> secondary_type = type; else secondary_type = in_p ?
> RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS; *picode =
> CODE_FOR_nothing; /* If X is a paradoxical SUBREG, use the inner
> value to determine both the mode and object being reloaded. */ if
> (GET_CODE (x) == SUBREG && (GET_MODE_SIZE (GET_MODE (x)) >
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) { x = SUBREG_REG (x);
> reload_mode = GET_MODE (x); } /* 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 (REG_P (x) && REGNO (x) >=
> FIRST_PSEUDO_REGISTER && reg_equiv_mem[REGNO (x)] != 0) x =
> reg_equiv_mem[REGNO (x)]; sri.icode = CODE_FOR_nothing;
> sri.prev_sri = prev_sri; class = targetm.secondary_reload (in_p, x,
> reload_class, reload_mode, &sri); icode = sri.icode; /* If we don't
> need any secondary registers, done. */ if (class == NO_REGS &&
> icode == CODE_FOR_nothing) return -1; if (class != NO_REGS)
> t_reload = push_secondary_reload (in_p, x, opnum, optional, class,
> reload_mode, type, &t_icode, &sri); /* If we will be using an insn,
> the secondary reload is for a scratch register. */ if (icode !=
> CODE_FOR_nothing) { /* If IN_P is nonzero, 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. */ /* ??? It would be useful to be able to
> handle only two, or more than three, operands, but for now we can
> only handle the case of having exactly three: output, input and one
> temp/scratch. */ gcc_assert (insn_data[(int) icode].n_operands ==
> 3); /* ??? We currently have no way to represent a reload that
> needs an icode to reload from an intermediate tertiary reload
> register. We should probably have a new field in struct reload to
> tag a chain of scratch operand reloads onto. */ gcc_assert (class
> == NO_REGS); scratch_constraint = insn_data[(int) icode].operand
> [2].constraint; gcc_assert (*scratch_constraint == '=');
> scratch_constraint++; if (*scratch_constraint == '&')
> scratch_constraint++; letter = *scratch_constraint; scratch_class =
> (letter == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT
> ((unsigned char) letter, scratch_constraint)); class =
> scratch_class; mode = insn_data[(int) icode].operand[2].mode; } /*
> This case isn't valid, so fail. Reload is allowed to use the same
> register for RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT reloads,
> but in the case of a secondary register, we actually need two
> different registers for correct code. We fail here to prevent the
> possibility of silently generating incorrect code later. The
> convention is that secondary input reloads are valid only if the
> secondary_class is different from class. If you have such a case,
> you can not use secondary reloads, you must work around the problem
> some other way. Allow this when a reload_in/out pattern is being
> used. I.e. assume that the generated code handles this case. */
> gcc_assert (!in_p || class != reload_class || icode !=
> CODE_FOR_nothing || t_icode != CODE_FOR_nothing); /* See if we can
> reuse an existing secondary reload. */ for (s_reload = 0; s_reload
> < n_reloads; s_reload++) if (rld[s_reload].secondary_p &&
> (reg_class_subset_p (class, rld[s_reload].class) ||
> reg_class_subset_p (rld[s_reload].class, class)) && ((in_p && rld
> [s_reload].inmode == mode) || (! in_p && rld[s_reload].outmode ==
> mode)) && ((in_p && rld[s_reload].secondary_in_reload == t_reload)
> || (! in_p && rld[s_reload].secondary_out_reload == t_reload)) &&
> ((in_p && rld[s_reload].secondary_in_icode == t_icode) || (! in_p
> && rld[s_reload].secondary_out_icode == t_icode)) &&
> (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES) &&
> MERGABLE_RELOADS (secondary_type, rld[s_reload].when_needed, opnum,
> rld[s_reload].opnum)) { if (in_p) rld[s_reload].inmode = mode; if
> (! in_p) rld[s_reload].outmode = mode; if (reg_class_subset_p
> (class, rld[s_reload].class)) rld[s_reload].class = class; rld
> [s_reload].opnum = MIN (rld[s_reload].opnum, opnum); rld
> [s_reload].optional &= optional; rld[s_reload].secondary_p = 1; if
> (MERGE_TO_OTHER (secondary_type, rld[s_reload].when_needed, opnum,
> rld[s_reload].opnum)) rld[s_reload].when_needed = RELOAD_OTHER; }
> if (s_reload == n_reloads) { #ifdef SECONDARY_MEMORY_NEEDED /* If
> we need a memory location to copy between the two reload regs, set
> it up now. Note that we do the input case before making the reload
> and the output case after. This is due to the way reloads are
> output. */ if (in_p && icode == CODE_FOR_nothing &&
> SECONDARY_MEMORY_NEEDED (class, reload_class, mode))
> { get_secondary_mem (x, reload_mode, opnum, type); /* We may have
> just added new reloads. Make sure we add the new reload at the end.
> */ s_reload = n_reloads; } #endif /* We need to make a new
> secondary reload for this register class. */ rld[s_reload].in = rld
> [s_reload].out = 0; rld[s_reload].class = class; rld
> [s_reload].inmode = in_p ? mode : VOIDmode; rld[s_reload].outmode
> = ! in_p ? mode : VOIDmode; rld[s_reload].reg_rtx = 0; rld
> [s_reload].optional = optional; rld[s_reload].inc = 0; /* Maybe we
> could combine these, but it seems too tricky. */ rld
> [s_reload].nocombine = 1; rld[s_reload].in_reg = 0; rld
> [s_reload].out_reg = 0; rld[s_reload].opnum = opnum; rld
> [s_reload].when_needed = secondary_type; rld
> [s_reload].secondary_in_reload = in_p ? t_reload : -1; rld
> [s_reload].secondary_out_reload = ! in_p ? t_reload : -1; rld
> [s_reload].secondary_in_icode = in_p ? t_icode : CODE_FOR_nothing;
> rld[s_reload].secondary_out_icode = ! in_p ? t_icode :
> CODE_FOR_nothing; rld[s_reload].secondary_p = 1; n_reloads++;
> #ifdef SECONDARY_MEMORY_NEEDED if (! in_p && icode ==
> CODE_FOR_nothing && SECONDARY_MEMORY_NEEDED (reload_class, class,
> mode)) get_secondary_mem (x, mode, opnum, type); #endif } *picode =
> icode; return s_reload; } /* If a secondary reload is needed,
> return its class. If both an intermediate register and a scratch
> register is needed, we return the class of the intermediate
> register. */ enum reg_class secondary_reload_class (bool in_p, enum
> reg_class class, enum machine_mode mode, rtx x) { enum insn_code
> icode; secondary_reload_info sri; sri.icode = CODE_FOR_nothing;
> sri.prev_sri = NULL; class = targetm.secondary_reload (in_p, x,
> class, mode, &sri); icode = sri.icode; /* If there are no secondary
> reloads at all, we return NO_REGS. If an intermediate register is
> needed, we return its class. */ if (icode == CODE_FOR_nothing ||
> class != NO_REGS) return class; /* No intermediate register is
> needed, but we have a special reload pattern, which we assume for
> now needs a scratch register. */ return scratch_reload_class
> (icode); } /* ICODE is the insn_code of a reload pattern. Check
> that it has exactly three operands, verify that operand 2 is an
> output operand, and return its register class. ??? We'd like to be
> able to handle any pattern with at least 2 operands, for zero or
> more scratch registers, but that needs more infrastructure. */ enum
> reg_class scratch_reload_class (enum insn_code icode) { const char
> *scratch_constraint; char scratch_letter; enum reg_class class;
> gcc_assert (insn_data[(int) icode].n_operands == 3);
> scratch_constraint = insn_data[(int) icode].operand[2].constraint;
> gcc_assert (*scratch_constraint == '='); scratch_constraint++; if
> (*scratch_constraint == '&') scratch_constraint++; scratch_letter =
> *scratch_constraint; if (scratch_letter == 'r') return
> GENERAL_REGS; class = REG_CLASS_FROM_CONSTRAINT ((unsigned char)
> scratch_letter, scratch_constraint); gcc_assert (class != NO_REGS);
> return class; } #ifdef SECONDARY_MEMORY_NEEDED /* Return a memory
> location that will be used to copy X in mode MODE. If we haven't
> already made a location for this mode in this insn, call
> find_reloads_address on the location being returned. */ rtx
> get_secondary_mem (rtx x ATTRIBUTE_UNUSED, enum machine_mode mode,
> int opnum, enum reload_type type) { rtx loc; int mem_valid; /* By
> default, if MODE is narrower than a word, widen it to a word. This
> is required because most machines that require these memory
> locations do not support short load and stores from all registers
> (e.g., FP registers). */ #ifdef SECONDARY_MEMORY_NEEDED_MODE mode =
> SECONDARY_MEMORY_NEEDED_MODE (mode); #else if (GET_MODE_BITSIZE
> (mode) < BITS_PER_WORD && INTEGRAL_MODE_P (mode)) mode =
> mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0); #endif /*
> If we already have made a MEM for this operand in MODE, return it.
> */ if (secondary_memlocs_elim[(int) mode][opnum] != 0) return
> secondary_memlocs_elim[(int) mode][opnum]; /* If this is the first
> time we've tried to get a MEM for this mode, allocate a new one.
> `something_changed' in reload will get set by noticing that the
> frame size has changed. */ if (secondary_memlocs[(int) mode] == 0)
> { #ifdef SECONDARY_MEMORY_NEEDED_RTX secondary_memlocs[(int) mode]
> = SECONDARY_MEMORY_NEEDED_RTX (mode); #else secondary_memlocs[(int)
> mode] = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
> #endif } /* Get a version of the address doing any eliminations
> needed. If that didn't give us a new MEM, make a new one if it
> isn't valid. */ loc = eliminate_regs (secondary_memlocs[(int)
> mode], VOIDmode, NULL_RTX); mem_valid = strict_memory_address_p
> (mode, XEXP (loc, 0)); if (! mem_valid && loc == secondary_memlocs
> [(int) mode]) loc = copy_rtx (loc); /* The only time the call below
> will do anything is if the stack offset is too large. In that case
> IND_LEVELS doesn't matter, so we can just pass a zero. Adjust the
> type to be the address of the corresponding object. If the address
> was valid, save the eliminated address. If it wasn't valid, we need
> to make a reload each time, so don't save it. */ if (! mem_valid)
> { type = (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS :
> type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS :
> RELOAD_OTHER); find_reloads_address (mode, &loc, XEXP (loc, 0),
> &XEXP (loc, 0), opnum, type, 0, 0); } secondary_memlocs_elim[(int)
> mode][opnum] = loc; if (secondary_memlocs_elim_used <= (int)mode)
> secondary_memlocs_elim_used = (int)mode + 1; return loc; } /* Clear
> any secondary memory locations we've made. */ void
> clear_secondary_mem (void) { memset (secondary_memlocs, 0, sizeof
> secondary_memlocs); } #endif /* SECONDARY_MEMORY_NEEDED */ /* Find
> the largest class which has at least one register valid in mode
> INNER, and which for every such register, that register number plus
> N is also valid in OUTER (if in range) and is cheap to move into
> REGNO. Such a class must exist. */ static enum reg_class
> find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED, enum
> machine_mode inner ATTRIBUTE_UNUSED, int n, unsigned int dest_regno
> ATTRIBUTE_UNUSED) { int best_cost = -1; int class; int regno; enum
> reg_class best_class = NO_REGS; enum reg_class dest_class
> ATTRIBUTE_UNUSED = REGNO_REG_CLASS (dest_regno); unsigned int
> best_size = 0; int cost; for (class = 1; class < N_REG_CLASSES;
> class++) { int bad = 0; int good = 0; for (regno = 0; regno <
> FIRST_PSEUDO_REGISTER - n && ! bad; regno++) if (TEST_HARD_REG_BIT
> (reg_class_contents[class], regno)) { if (HARD_REGNO_MODE_OK
> (regno, inner)) { good = 1; if (! TEST_HARD_REG_BIT
> (reg_class_contents[class], regno + n) || ! HARD_REGNO_MODE_OK
> (regno + n, outer)) bad = 1; } } if (bad || !good) continue; cost =
> REGISTER_MOVE_COST (outer, class, dest_class); if ((reg_class_size
> [class] > best_size && (best_cost < 0 || best_cost >= cost)) ||
> best_cost > cost) { best_class = class; best_size = reg_class_size
> [class]; best_cost = REGISTER_MOVE_COST (outer, class,
> dest_class); } } gcc_assert (best_size != 0); return best_class; } /
> * Return the number of a previously made reload that can be
> combined with a new one, or n_reloads if none of the existing
> reloads can be used. OUT, CLASS, TYPE and OPNUM are the same
> arguments as passed to push_reload, they determine the kind of the
> new reload that we try to combine. P_IN points to the corresponding
> value of IN, which can be modified by this function. DONT_SHARE is
> nonzero if we can't share any input-only reload for IN. */ static
> int find_reusable_reload (rtx *p_in, rtx out, enum reg_class class,
> enum reload_type type, int opnum, int dont_share) { rtx in = *p_in;
> int i; /* We can't merge two reloads if the output of either one is
> earlyclobbered. */ if (earlyclobber_operand_p (out)) return
> n_reloads; /* We can use an existing reload if the class is right
> and at least one of IN and OUT is a match and the other is at worst
> neutral. (A zero compared against anything is neutral.) If
> SMALL_REGISTER_CLASSES, don't use existing reloads unless they are
> for the same thing since that can cause us to need more reload
> registers than we otherwise would. */ for (i = 0; i < n_reloads; i+
> +) if ((reg_class_subset_p (class, rld[i].class) ||
> reg_class_subset_p (rld[i].class, class)) /* If the existing reload
> has a register, it must fit our class. */ && (rld[i].reg_rtx == 0
> || TEST_HARD_REG_BIT (reg_class_contents[(int) class], true_regnum
> (rld[i].reg_rtx))) && ((in != 0 && MATCHES (rld[i].in, in) && !
> dont_share && (out == 0 || rld[i].out == 0 || MATCHES (rld[i].out,
> out))) || (out != 0 && MATCHES (rld[i].out, out) && (in == 0 || rld
> [i].in == 0 || MATCHES (rld[i].in, in)))) && (rld[i].out == 0 || !
> earlyclobber_operand_p (rld[i].out)) && (SMALL_REGISTER_CLASS_P
> (class) || SMALL_REGISTER_CLASSES) && MERGABLE_RELOADS (type, rld
> [i].when_needed, opnum, rld[i].opnum)) return i; /* Reloading a
> plain reg for input can match a reload to postincrement that reg,
> since the postincrement's value is the right value. Likewise, it
> can match a preincrement reload, since we regard the
> preincrementation as happening before any ref in this insn to that
> register. */ for (i = 0; i < n_reloads; i++) if
> ((reg_class_subset_p (class, rld[i].class) || reg_class_subset_p
> (rld[i].class, class)) /* If the existing reload has a register, it
> must fit our class. */ && (rld[i].reg_rtx == 0 || TEST_HARD_REG_BIT
> (reg_class_contents[(int) class], true_regnum (rld[i].reg_rtx))) &&
> out == 0 && rld[i].out == 0 && rld[i].in != 0 && ((REG_P (in) &&
> GET_RTX_CLASS (GET_CODE (rld[i].in)) == RTX_AUTOINC && MATCHES
> (XEXP (rld[i].in, 0), in)) || (REG_P (rld[i].in) && GET_RTX_CLASS
> (GET_CODE (in)) == RTX_AUTOINC && MATCHES (XEXP (in, 0), rld
> [i].in))) && (rld[i].out == 0 || ! earlyclobber_operand_p (rld
> [i].out)) && (SMALL_REGISTER_CLASS_P (class) ||
> SMALL_REGISTER_CLASSES) && MERGABLE_RELOADS (type, rld
> [i].when_needed, opnum, rld[i].opnum)) { /* Make sure reload_in
> ultimately has the increment, not the plain register. */ if (REG_P
> (in)) *p_in = rld[i].in; return i; } return n_reloads; } /* Return
> nonzero if X is a SUBREG which will require reloading of its
> SUBREG_REG expression. */ static int reload_inner_reg_of_subreg
> (rtx x, enum machine_mode mode, int output) { rtx inner; /* Only
> SUBREGs are problematical. */ if (GET_CODE (x) != SUBREG) return 0;
> inner = SUBREG_REG (x); /* If INNER is a constant or PLUS, then
> INNER must be reloaded. */ if (CONSTANT_P (inner) || GET_CODE
> (inner) == PLUS) return 1; /* If INNER is not a hard register, then
> INNER will not need to be reloaded. */ if (!REG_P (inner) || REGNO
> (inner) >= FIRST_PSEUDO_REGISTER) return 0; /* If INNER is not ok
> for MODE, then INNER will need reloading. */ if (!
> HARD_REGNO_MODE_OK (subreg_regno (x), mode)) return 1; /* If the
> outer part is a word or smaller, INNER larger than a word and the
> number of regs for INNER is not the same as the number of words in
> INNER, then INNER will need reloading. */ return (GET_MODE_SIZE
> (mode) <= UNITS_PER_WORD && output && GET_MODE_SIZE (GET_MODE
> (inner)) > UNITS_PER_WORD && ((GET_MODE_SIZE (GET_MODE (inner)) /
> UNITS_PER_WORD) != (int) hard_regno_nregs[REGNO (inner)][GET_MODE
> (inner)])); } /* Return nonzero if IN can be reloaded into REGNO
> with mode MODE without requiring an extra reload register. The
> caller has already found that IN contains some reference to REGNO,
> so check that we can produce the new value in a single step. E.g.
> if we have (set (reg r13) (plus (reg r13) (const int 1))), and
> there is an instruction that adds one to a register, this should
> succeed. However, if we have something like (set (reg r13) (plus
> (reg r13) (const int 999))), and the constant 999 needs to be
> loaded into a register first, we need a separate reload register.
> Such PLUS reloads are generated by find_reload_address_part. The
> out-of-range PLUS expressions are usually introduced in the
> instruction patterns by register elimination and substituting
> pseudos without a home by their function-invariant equivalences. */
> static int can_reload_into (rtx in, int regno, enum machine_mode
> mode) { rtx dst, test_insn; int r = 0; struct recog_data
> save_recog_data; /* For matching constraints, we often get notional
> input reloads where we want to use the original register as the
> reload register. I.e. technically this is a non-optional input-
> output reload, but IN is already a valid register, and has been
> chosen as the reload register. Speed this up, since it trivially
> works. */ if (REG_P (in)) return 1; /* To test MEMs properly, we'd
> have to take into account all the reloads that are already
> scheduled, which can become quite complicated. And since we've
> already handled address reloads for this MEM, it should always
> succeed anyway. */ if (MEM_P (in)) return 1; /* If we can make a
> simple SET insn that does the job, everything should be fine. */
> dst = gen_rtx_REG (mode, regno); test_insn = make_insn_raw
> (gen_rtx_SET (VOIDmode, dst, in)); save_recog_data = recog_data; if
> (recog_memoized (test_insn) >= 0) { extract_insn (test_insn); r =
> constrain_operands (1); } recog_data = save_recog_data; return
> r; } /* Record one reload that needs to be performed. IN is an rtx
> saying where the data are to be found before this instruction. OUT
> says where they must be stored after the instruction. (IN is zero
> for data not read, and OUT is zero for data not written.) INLOC and
> OUTLOC point to the places in the instructions where IN and OUT
> were found. If IN and OUT are both nonzero, it means the same
> register must be used to reload both IN and OUT. CLASS is a
> register class required for the reloaded data. INMODE is the
> machine mode that the instruction requires for the reg that
> replaces IN and OUTMODE is likewise for OUT. If IN is zero, then
> OUT's location and mode should be passed as INLOC and INMODE.
> STRICT_LOW is the 1 if there is a containing STRICT_LOW_PART rtx.
> OPTIONAL nonzero means this reload does not need to be performed:
> it can be discarded if that is more convenient. OPNUM and TYPE say
> what the purpose of this reload is. The return value is the reload-
> number for this reload. If both IN and OUT are nonzero, in some
> rare cases we might want to make two separate reloads. (Actually we
> never do this now.) Therefore, the reload-number for OUT is stored
> in output_reloadnum when we return; the return value applies to IN.
> Usually (presently always), when IN and OUT are nonzero, the two
> reload-numbers are equal, but the caller should be careful to
> distinguish them. */ int push_reload (rtx in, rtx out, rtx *inloc,
> rtx *outloc, enum reg_class class, enum machine_mode inmode, enum
> machine_mode outmode, int strict_low, int optional, int opnum, enum
> reload_type type) { int i; int dont_share = 0; int
> dont_remove_subreg = 0; rtx *in_subreg_loc = 0, *out_subreg_loc =
> 0; int secondary_in_reload = -1, secondary_out_reload = -1; enum
> insn_code secondary_in_icode = CODE_FOR_nothing; enum insn_code
> secondary_out_icode = CODE_FOR_nothing; /* INMODE and/or OUTMODE
> could be VOIDmode if no mode has been specified for the operand. In
> that case, use the operand's mode as the mode to reload. */ if
> (inmode == VOIDmode && in != 0) inmode = GET_MODE (in); if (outmode
> == VOIDmode && out != 0) outmode = GET_MODE (out); /* If IN is a
> pseudo register everywhere-equivalent to a constant, and it is not
> in a hard register, reload straight from the constant, since we
> want to get rid of such pseudo registers. Often this is done
> earlier, but not always in find_reloads_address. */ if (in != 0 &&
> REG_P (in)) { int regno = REGNO (in); if (regno >=
> FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 &&
> reg_equiv_constant[regno] != 0) in = reg_equiv_constant[regno]; } /
> * Likewise for OUT. Of course, OUT will never be equivalent to an
> actual constant, but it might be equivalent to a memory location
> (in the case of a parameter). */ if (out != 0 && REG_P (out)) { int
> regno = REGNO (out); if (regno >= FIRST_PSEUDO_REGISTER &&
> reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0) out =
> reg_equiv_constant[regno]; } /* If we have a read-write operand
> with an address side-effect, change either IN or OUT so the side-
> effect happens only once. */ if (in != 0 && out != 0 && MEM_P (in)
> && rtx_equal_p (in, out)) switch (GET_CODE (XEXP (in, 0))) { case
> POST_INC: case POST_DEC: case POST_MODIFY: in =
> replace_equiv_address_nv (in, XEXP (XEXP (in, 0), 0)); break; case
> PRE_INC: case PRE_DEC: case PRE_MODIFY: out =
> replace_equiv_address_nv (out, XEXP (XEXP (out, 0), 0)); break;
> default: break; } /* If we are reloading a (SUBREG constant ...),
> really reload just the inside expression in its own mode. Similarly
> for (SUBREG (PLUS ...)). If we have (SUBREG:M1 (MEM:M2 ...) ...)
> (or an inner REG that is still a pseudo and hence will become a
> MEM) with M1 wider than M2 and the register is a pseudo, also
> reload the inside expression. For machines that extend byte loads,
> do this for any SUBREG of a pseudo where both M1 and M2 are a word
> or smaller, M1 is wider than M2, and M2 is an integral mode that
> gets extended when loaded. Similar issue for (SUBREG:M1
> (REG:M2 ...) ...) for a hard register R where either M1 is not
> valid for R or M2 is wider than a word but we only need one word to
> store an M2-sized quantity in R. (However, if OUT is nonzero, we
> need to reload the reg *and* the subreg, so do nothing here, and
> let following statement handle it.) Note that the case of (SUBREG
> (CONST_INT...)...) is handled elsewhere; we can't handle it here
> because CONST_INT does not indicate a mode. Similarly, we must
> reload the inside expression if we have a STRICT_LOW_PART
> (presumably, in == out in the cas). Also reload the inner
> expression if it does not require a secondary reload but the SUBREG
> does. Finally, reload the inner expression if it is a register that
> is in the class whose registers cannot be referenced in a different
> size and M1 is not the same size as M2. If subreg_lowpart_p is
> false, we cannot reload just the inside since we might end up with
> the wrong register class. But if it is inside a STRICT_LOW_PART, we
> have no choice, so we hope we do get the right register class
> there. */ if (in != 0 && GET_CODE (in) == SUBREG &&
> (subreg_lowpart_p (in) || strict_low) #ifdef
> CANNOT_CHANGE_MODE_CLASS && !CANNOT_CHANGE_MODE_CLASS (GET_MODE
> (SUBREG_REG (in)), inmode, class) #endif && (CONSTANT_P (SUBREG_REG
> (in)) || GET_CODE (SUBREG_REG (in)) == PLUS || strict_low ||
> (((REG_P (SUBREG_REG (in)) && REGNO (SUBREG_REG (in)) >=
> FIRST_PSEUDO_REGISTER) || MEM_P (SUBREG_REG (in))) &&
> ((GET_MODE_SIZE (inmode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG
> (in)))) #ifdef LOAD_EXTEND_OP || (GET_MODE_SIZE (inmode) <=
> UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) <=
> UNITS_PER_WORD) && (GET_MODE_SIZE (inmode) > GET_MODE_SIZE
> (GET_MODE (SUBREG_REG (in)))) && INTEGRAL_MODE_P (GET_MODE
> (SUBREG_REG (in))) && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) !
> = UNKNOWN) #endif #ifdef WORD_REGISTER_OPERATIONS ||
> ((GET_MODE_SIZE (inmode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG
> (in)))) && ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD ==
> ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1) /
> UNITS_PER_WORD))) #endif )) || (REG_P (SUBREG_REG (in)) && REGNO
> (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER /* The case where out is
> nonzero is handled differently in the following statement. */ &&
> (out == 0 || subreg_lowpart_p (in)) && ((GET_MODE_SIZE (inmode) <=
> UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) >
> UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) /
> UNITS_PER_WORD) != (int) hard_regno_nregs[REGNO (SUBREG_REG (in))]
> [GET_MODE (SUBREG_REG (in))])) || ! HARD_REGNO_MODE_OK
> (subreg_regno (in), inmode))) || (secondary_reload_class (1, class,
> inmode, in) != NO_REGS && (secondary_reload_class (1, class,
> GET_MODE (SUBREG_REG (in)), SUBREG_REG (in)) == NO_REGS)) #ifdef
> CANNOT_CHANGE_MODE_CLASS || (REG_P (SUBREG_REG (in)) && REGNO
> (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER &&
> REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (in)), GET_MODE
> (SUBREG_REG (in)), inmode)) #endif )) { in_subreg_loc = inloc;
> inloc = &SUBREG_REG (in); in = *inloc; #if ! defined
> (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) if (MEM_P
> (in)) /* This is supposed to happen only for paradoxical subregs
> made by combine.c. (SUBREG (MEM)) isn't supposed to occur other
> ways. */ gcc_assert (GET_MODE_SIZE (GET_MODE (in)) <= GET_MODE_SIZE
> (inmode)); #endif inmode = GET_MODE (in); } /* Similar issue for
> (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where either M1
> is not valid for R or M2 is wider than a word but we only need one
> word to store an M2-sized quantity in R. However, we must reload
> the inner reg *as well as* the subreg in that case. */ /* Similar
> issue for (SUBREG constant ...) if it was not handled by the code
> above. This can happen if SUBREG_BYTE != 0. */ if (in != 0 &&
> reload_inner_reg_of_subreg (in, inmode, 0)) { enum reg_class
> in_class = class; if (REG_P (SUBREG_REG (in))) in_class =
> find_valid_class (inmode, GET_MODE (SUBREG_REG (in)),
> subreg_regno_offset (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG
> (in)), SUBREG_BYTE (in), GET_MODE (in)), REGNO (SUBREG_REG (in))); /
> * This relies on the fact that emit_reload_insns outputs the
> instructions for input reloads of type RELOAD_OTHER in the same
> order as the reloads. Thus if the outer reload is also of type
> RELOAD_OTHER, we are guaranteed that this inner reload will be
> output before the outer reload. */ push_reload (SUBREG_REG (in),
> NULL_RTX, &SUBREG_REG (in), (rtx *) 0, in_class, VOIDmode,
> VOIDmode, 0, 0, opnum, type); dont_remove_subreg = 1; } /*
> Similarly for paradoxical and problematical SUBREGs on the output.
> Note that there is no reason we need worry about the previous value
> of SUBREG_REG (out); even if wider than out, storing in a subreg is
> entitled to clobber it all (except in the case of STRICT_LOW_PART,
> and in that case the constraint should label it input-output.) */
> if (out != 0 && GET_CODE (out) == SUBREG && (subreg_lowpart_p (out)
> || strict_low) #ifdef CANNOT_CHANGE_MODE_CLASS && !
> CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode,
> class) #endif && (CONSTANT_P (SUBREG_REG (out)) || strict_low ||
> (((REG_P (SUBREG_REG (out)) && REGNO (SUBREG_REG (out)) >=
> FIRST_PSEUDO_REGISTER) || MEM_P (SUBREG_REG (out))) &&
> ((GET_MODE_SIZE (outmode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG
> (out)))) #ifdef WORD_REGISTER_OPERATIONS || ((GET_MODE_SIZE
> (outmode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))) &&
> ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD == ((GET_MODE_SIZE
> (GET_MODE (SUBREG_REG (out))) - 1) / UNITS_PER_WORD))) #endif )) ||
> (REG_P (SUBREG_REG (out)) && REGNO (SUBREG_REG (out)) <
> FIRST_PSEUDO_REGISTER && ((GET_MODE_SIZE (outmode) <=
> UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) >
> UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) /
> UNITS_PER_WORD) != (int) hard_regno_nregs[REGNO (SUBREG_REG (out))]
> [GET_MODE (SUBREG_REG (out))])) || ! HARD_REGNO_MODE_OK
> (subreg_regno (out), outmode))) || (secondary_reload_class (0,
> class, outmode, out) != NO_REGS && (secondary_reload_class (0,
> class, GET_MODE (SUBREG_REG (out)), SUBREG_REG (out)) == NO_REGS))
> #ifdef CANNOT_CHANGE_MODE_CLASS || (REG_P (SUBREG_REG (out)) &&
> REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER &&
> REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), GET_MODE
> (SUBREG_REG (out)), outmode)) #endif )) { out_subreg_loc = outloc;
> outloc = &SUBREG_REG (out); out = *outloc; #if ! defined
> (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) gcc_assert
> (!MEM_P (out) || GET_MODE_SIZE (GET_MODE (out)) <= GET_MODE_SIZE
> (outmode)); #endif outmode = GET_MODE (out); } /* Similar issue for
> (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where either M1
> is not valid for R or M2 is wider than a word but we only need one
> word to store an M2-sized quantity in R. However, we must reload
> the inner reg *as well as* the subreg in that case. In this case,
> the inner reg is an in-out reload. */ if (out != 0 &&
> reload_inner_reg_of_subreg (out, outmode, 1)) { /* This relies on
> the fact that emit_reload_insns outputs the instructions for output
> reloads of type RELOAD_OTHER in reverse order of the reloads. Thus
> if the outer reload is also of type RELOAD_OTHER, we are guaranteed
> that this inner reload will be output after the outer reload. */
> dont_remove_subreg = 1; push_reload (SUBREG_REG (out), SUBREG_REG
> (out), &SUBREG_REG (out), &SUBREG_REG (out), find_valid_class
> (outmode, GET_MODE (SUBREG_REG (out)), subreg_regno_offset (REGNO
> (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out)), SUBREG_BYTE (out),
> GET_MODE (out)), REGNO (SUBREG_REG (out))), VOIDmode, VOIDmode, 0,
> 0, opnum, RELOAD_OTHER); } /* If IN appears in OUT, we can't share
> any input-only reload for IN. */ if (in != 0 && out != 0 && MEM_P
> (out) && (REG_P (in) || MEM_P (in)) &&
> reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0))) dont_share
> = 1; /* If IN is a SUBREG of a hard register, make a new REG. This
> simplifies some of the cases below. */ if (in != 0 && GET_CODE (in)
> == SUBREG && REG_P (SUBREG_REG (in)) && REGNO (SUBREG_REG (in)) <
> FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) in = gen_rtx_REG
> (GET_MODE (in), subreg_regno (in)); /* Similarly for OUT. */ if
> (out != 0 && GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out))
> && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && !
> dont_remove_subreg) out = gen_rtx_REG (GET_MODE (out), subreg_regno
> (out)); /* Narrow down the class of register wanted if that is
> desirable on this machine for efficiency. */ { enum reg_class
> preferred_class = class; if (in != 0) preferred_class =
> PREFERRED_RELOAD_CLASS (in, class); /* Output reloads may need
> analogous treatment, different in detail. */ #ifdef
> PREFERRED_OUTPUT_RELOAD_CLASS if (out != 0) preferred_class =
> PREFERRED_OUTPUT_RELOAD_CLASS (out, preferred_class); #endif /*
> Discard what the target said if we cannot do it. */ if
> (preferred_class != NO_REGS || (optional && type ==
> RELOAD_FOR_OUTPUT)) class = preferred_class; } /* Make sure we use
> a class that can handle the actual pseudo inside any subreg. For
> example, on the 386, QImode regs can appear within SImode subregs.
> Although GENERAL_REGS can handle SImode, QImode needs a smaller
> class. */ #ifdef LIMIT_RELOAD_CLASS if (in_subreg_loc) class =
> LIMIT_RELOAD_CLASS (inmode, class); else if (in != 0 && GET_CODE
> (in) == SUBREG) class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG
> (in)), class); if (out_subreg_loc) class = LIMIT_RELOAD_CLASS
> (outmode, class); if (out != 0 && GET_CODE (out) == SUBREG) class =
> LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), class); #endif /*
> Verify that this class is at least possible for the mode that is
> specified. */ if (this_insn_is_asm) { enum machine_mode mode; if
> (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode)) mode = inmode;
> else mode = outmode; if (mode == VOIDmode) { error_for_asm
> (this_insn, "cannot reload integer constant " "operand in %<asm%
> >"); mode = word_mode; if (in != 0) inmode = word_mode; if (out !=
> 0) outmode = word_mode; } for (i = 0; i < FIRST_PSEUDO_REGISTER; i+
> +) if (HARD_REGNO_MODE_OK (i, mode) && TEST_HARD_REG_BIT
> (reg_class_contents[(int) class], i)) { int nregs = hard_regno_nregs
> [i][mode]; int j; for (j = 1; j < nregs; j++) if (!
> TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j)) break;
> if (j == nregs) break; } if (i == FIRST_PSEUDO_REGISTER)
> { error_for_asm (this_insn, "impossible register constraint " "in %
> <asm%>"); /* Avoid further trouble with this insn. */ PATTERN
> (this_insn) = gen_rtx_USE (VOIDmode, const0_rtx); /* We used to
> continue here setting class to ALL_REGS, but it triggers sanity
> check on i386 for: void foo(long double d) { asm("" :: "a" (d)); }
> Returning zero here ought to be safe as we take care in
> find_reloads to not process the reloads when instruction was
> replaced by USE. */ return 0; } } /* Optional output reloads are
> always OK even if we have no register class, since the function of
> these reloads is only to have spill_reg_store etc. set, so that the
> storing insn can be deleted later. */ gcc_assert (class != NO_REGS
> || (optional != 0 && type == RELOAD_FOR_OUTPUT)); i =
> find_reusable_reload (&in, out, class, type, opnum, dont_share); if
> (i == n_reloads) { /* See if we need a secondary reload register to
> move between CLASS and IN or CLASS and OUT. Get the icode and push
> any required reloads needed for each of them if so. */ if (in != 0)
> secondary_in_reload = push_secondary_reload (1, in, opnum,
> optional, class, inmode, type, &secondary_in_icode, NULL); if (out !
> = 0 && GET_CODE (out) != SCRATCH) secondary_out_reload =
> push_secondary_reload (0, out, opnum, optional, class, outmode,
> type, &secondary_out_icode, NULL); /* We found no existing reload
> suitable for re-use. So add an additional reload. */ #ifdef
> SECONDARY_MEMORY_NEEDED /* If a memory location is needed for the
> copy, make one. */ if (in != 0 && (REG_P (in) || (GET_CODE (in) ==
> SUBREG && REG_P (SUBREG_REG (in)))) && reg_or_subregno (in) <
> FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS
> (reg_or_subregno (in)), class, inmode)) get_secondary_mem (in,
> inmode, opnum, type); #endif i = n_reloads; rld[i].in = in; rld
> [i].out = out; rld[i].class = class; rld[i].inmode = inmode; rld
> [i].outmode = outmode; rld[i].reg_rtx = 0; rld[i].optional =
> optional; rld[i].inc = 0; rld[i].nocombine = 0; rld[i].in_reg =
> inloc ? *inloc : 0; rld[i].out_reg = outloc ? *outloc : 0; rld
> [i].opnum = opnum; rld[i].when_needed = type; rld
> [i].secondary_in_reload = secondary_in_reload; rld
> [i].secondary_out_reload = secondary_out_reload; rld
> [i].secondary_in_icode = secondary_in_icode; rld
> [i].secondary_out_icode = secondary_out_icode; rld[i].secondary_p =
> 0; n_reloads++; #ifdef SECONDARY_MEMORY_NEEDED if (out != 0 &&
> (REG_P (out) || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG
> (out)))) && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER &&
> SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (reg_or_subregno
> (out)), outmode)) get_secondary_mem (out, outmode, opnum, type);
> #endif } else { /* We are reusing an existing reload, but we may
> have additional information for it. For example, we may now have
> both IN and OUT while the old one may have just one of them. */ /*
> The modes can be different. If they are, we want to reload in the
> larger mode, so that the value is valid for both modes. */ if
> (inmode != VOIDmode && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (rld
> [i].inmode)) rld[i].inmode = inmode; if (outmode != VOIDmode &&
> GET_MODE_SIZE (outmode) > GET_MODE_SIZE (rld[i].outmode)) rld
> [i].outmode = outmode; if (in != 0) { rtx in_reg = inloc ? *inloc :
> 0; /* If we merge reloads for two distinct rtl expressions that are
> identical in content, there might be duplicate address reloads.
> Remove the extra set now, so that if we later find that we can
> inherit this reload, we can get rid of the address reloads
> altogether. Do not do this if both reloads are optional since the
> result would be an optional reload which could potentially leave
> unresolved address replacements. It is not sufficient to call
> transfer_replacements since choose_reload_regs will remove the
> replacements for address reloads of inherited reloads which results
> in the same problem. */ if (rld[i].in != in && rtx_equal_p (in, rld
> [i].in) && ! (rld[i].optional && optional)) { /* We must keep the
> address reload with the lower operand number alive. */ if (opnum >
> rld[i].opnum) { remove_address_replacements (in); in = rld[i].in;
> in_reg = rld[i].in_reg; } else remove_address_replacements (rld
> [i].in); } rld[i].in = in; rld[i].in_reg = in_reg; } if (out != 0)
> { rld[i].out = out; rld[i].out_reg = outloc ? *outloc : 0; } if
> (reg_class_subset_p (class, rld[i].class)) rld[i].class = class; rld
> [i].optional &= optional; if (MERGE_TO_OTHER (type, rld
> [i].when_needed, opnum, rld[i].opnum)) rld[i].when_needed =
> RELOAD_OTHER; rld[i].opnum = MIN (rld[i].opnum, opnum); } /* If the
> ostensible rtx being reloaded differs from the rtx found in the
> location to substitute, this reload is not safe to combine because
> we cannot reliably tell whether it appears in the insn. */ if (in !
> = 0 && in != *inloc) rld[i].nocombine = 1; #if 0 /* This was
> replaced by changes in find_reloads_address_1 and the new function
> inc_for_reload, which go with a new meaning of reload_inc. */ /* If
> this is an IN/OUT reload in an insn that sets the CC, it must be
> for an autoincrement. It doesn't work to store the incremented
> value after the insn because that would clobber the CC. So we must
> do the increment of the value reloaded from, increment it, store it
> back, then decrement again. */ if (out != 0 && sets_cc0_p (PATTERN
> (this_insn))) { out = 0; rld[i].out = 0; rld[i].inc =
> find_inc_amount (PATTERN (this_insn), in); /* If we did not find a
> nonzero amount-to-increment-by, that contradicts the belief that IN
> is being incremented in an address in this insn. */ gcc_assert (rld
> [i].inc != 0); } #endif /* If we will replace IN and OUT with the
> reload-reg, record where they are located so that substitution need
> not do a tree walk. */ if (replace_reloads) { if (inloc != 0)
> { struct replacement *r = &replacements[n_replacements++]; r->what
> = i; r->subreg_loc = in_subreg_loc; r->where = inloc; r->mode =
> inmode; } if (outloc != 0 && outloc != inloc) { struct replacement
> *r = &replacements[n_replacements++]; r->what = i; r->where =
> outloc; r->subreg_loc = out_subreg_loc; r->mode = outmode; } } /*
> If this reload is just being introduced and it has both an incoming
> quantity and an outgoing quantity that are supposed to be made to
> match, see if either one of the two can serve as the place to
> reload into. If one of them is acceptable, set rld[i].reg_rtx to
> that one. */ if (in != 0 && out != 0 && in != out && rld[i].reg_rtx
> == 0) { rld[i].reg_rtx = find_dummy_reload (in, out, inloc, outloc,
> inmode, outmode, rld[i].class, i, earlyclobber_operand_p (out)); /*
> If the outgoing register already contains the same value as the
> incoming one, we can dispense with loading it. The easiest way to
> tell the caller that is to give a phony value for the incoming
> operand (same as outgoing one). */ if (rld[i].reg_rtx == out &&
> (REG_P (in) || CONSTANT_P (in)) && 0 != find_equiv_reg (in,
> this_insn, 0, REGNO (out), static_reload_reg_p, i, inmode)) rld
> [i].in = out; } /* If this is an input reload and the operand
> contains a register that dies in this insn and is used nowhere
> else, see if it is the right class to be used for this reload. Use
> it if so. (This occurs most commonly in the case of paradoxical
> SUBREGs and in-out reloads). We cannot do this if it is also an
> output reload that mentions the register unless the output is a
> SUBREG that clobbers an entire register. Note that the operand
> might be one of the spill regs, if it is a pseudo reg and we are in
> a block where spilling has not taken place. But if there is no
> spilling in this block, that is OK. An explicitly used hard reg
> cannot be a spill reg. */ if (rld[i].reg_rtx == 0 && in != 0 &&
> hard_regs_live_known) { rtx note; int regno; enum machine_mode
> rel_mode = inmode; if (out && GET_MODE_SIZE (outmode) >
> GET_MODE_SIZE (inmode)) rel_mode = outmode; for (note = REG_NOTES
> (this_insn); note; note = XEXP (note, 1)) if (REG_NOTE_KIND (note)
> == REG_DEAD && REG_P (XEXP (note, 0)) && (regno = REGNO (XEXP
> (note, 0))) < FIRST_PSEUDO_REGISTER && reg_mentioned_p (XEXP (note,
> 0), in) /* Check that we don't use a hardreg for an uninitialized
> pseudo. See also find_dummy_reload(). */ && (ORIGINAL_REGNO (XEXP
> (note, 0)) < FIRST_PSEUDO_REGISTER || ! bitmap_bit_p
> (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, ORIGINAL_REGNO (XEXP
> (note, 0)))) && ! refers_to_regno_for_reload_p (regno, (regno +
> hard_regno_nregs[regno] [rel_mode]), PATTERN (this_insn), inloc) /*
> If this is also an output reload, IN cannot be used as the reload
> register if it is set in this insn unless IN is also OUT. */ &&
> (out == 0 || in == out || ! hard_reg_set_here_p (regno, (regno +
> hard_regno_nregs[regno] [rel_mode]), PATTERN (this_insn))) /* ???
> Why is this code so different from the previous? Is there any
> simple coherent way to describe the two together? What's going on
> here. */ && (in != out || (GET_CODE (in) == SUBREG &&
> (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1)) /
> UNITS_PER_WORD) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) +
> (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))) /* Make sure the operand
> fits in the reg that dies. */ && (GET_MODE_SIZE (rel_mode) <=
> GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))) && HARD_REGNO_MODE_OK
> (regno, inmode) && HARD_REGNO_MODE_OK (regno, outmode)) { unsigned
> int offs; unsigned int nregs = MAX (hard_regno_nregs[regno]
> [inmode], hard_regno_nregs[regno][outmode]); for (offs = 0; offs <
> nregs; offs++) if (fixed_regs[regno + offs] || ! TEST_HARD_REG_BIT
> (reg_class_contents[(int) class], regno + offs)) break; if (offs ==
> nregs && (! (refers_to_regno_for_reload_p (regno, (regno +
> hard_regno_nregs[regno][inmode]), in, (rtx *)0)) || can_reload_into
> (in, regno, inmode))) { rld[i].reg_rtx = gen_rtx_REG (rel_mode,
> regno); break; } } } if (out) output_reloadnum = i; return i; } /*
> Record an additional place we must replace a value for which we
> have already recorded a reload. RELOADNUM is the value returned by
> push_reload when the reload was recorded. This is used in insn
> patterns that use match_dup. */ static void push_replacement (rtx
> *loc, int reloadnum, enum machine_mode mode) { if (replace_reloads)
> { struct replacement *r = &replacements[n_replacements++]; r->what
> = reloadnum; r->where = loc; r->subreg_loc = 0; r->mode =
> mode; } } /* Duplicate any replacement we have recorded to apply at
> location ORIG_LOC to also be performed at DUP_LOC. This is used in
> insn patterns that use match_dup. */ static void dup_replacements
> (rtx *dup_loc, rtx *orig_loc) { int i, n = n_replacements; for (i =
> 0; i < n; i++) { struct replacement *r = &replacements[i]; if (r-
> >where == orig_loc) push_replacement (dup_loc, r->what, r-
> >mode); } } /* Transfer all replacements that used to be in reload
> FROM to be in reload TO. */ void transfer_replacements (int to, int
> from) { int i; for (i = 0; i < n_replacements; i++) if (replacements
> [i].what == from) replacements[i].what = to; } /* IN_RTX is the
> value loaded by a reload that we now decided to inherit, or a
> subpart of it. If we have any replacements registered for IN_RTX,
> cancel the reloads that were supposed to load them. Return nonzero
> if we canceled any reloads. */ int remove_address_replacements (rtx
> in_rtx) { int i, j; char reload_flags[MAX_RELOADS]; int
> something_changed = 0; memset (reload_flags, 0, sizeof
> reload_flags); for (i = 0, j = 0; i < n_replacements; i++) { if
> (loc_mentioned_in_p (replacements[i].where, in_rtx)) reload_flags
> [replacements[i].what] |= 1; else { replacements[j++] = replacements
> [i]; reload_flags[replacements[i].what] |= 2; } } /* Note that the
> following store must be done before the recursive calls. */
> n_replacements = j; for (i = n_reloads - 1; i >= 0; i--) { if
> (reload_flags[i] == 1) { deallocate_reload_reg (i);
> remove_address_replacements (rld[i].in); rld[i].in = 0;
> something_changed = 1; } } return something_changed; } /* If there
> is only one output reload, and it is not for an earlyclobber
> operand, try to combine it with a (logically unrelated) input
> reload to reduce the number of reload registers needed. This is
> safe if the input reload does not appear in the value being output-
> reloaded, because this implies it is not needed any more once the
> original insn completes. If that doesn't work, see we can use any
> of the registers that die in this insn as a reload register. We can
> if it is of the right class and does not appear in the value being
> output-reloaded. */ static void combine_reloads (void) { int i; int
> output_reload = -1; int secondary_out = -1; rtx note; /* Find the
> output reload; return unless there is exactly one and that one is
> mandatory. */ for (i = 0; i < n_reloads; i++) if (rld[i].out != 0)
> { if (output_reload >= 0) return; output_reload = i; } if
> (output_reload < 0 || rld[output_reload].optional) return; /* An
> input-output reload isn't combinable. */ if (rld[output_reload].in !
> = 0) return; /* If this reload is for an earlyclobber operand, we
> can't do anything. */ if (earlyclobber_operand_p (rld
> [output_reload].out)) return; /* If there is a reload for part of
> the address of this operand, we would need to chnage it to
> RELOAD_FOR_OTHER_ADDRESS. But that would extend its life to the
> point where doing this combine would not lower the number of spill
> registers needed. */ for (i = 0; i < n_reloads; i++) if ((rld
> [i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS || rld[i].when_needed
> == RELOAD_FOR_OUTADDR_ADDRESS) && rld[i].opnum == rld
> [output_reload].opnum) return; /* Check each input reload; can we
> combine it? */ for (i = 0; i < n_reloads; i++) if (rld[i].in && !
> rld[i].optional && ! rld[i].nocombine /* Life span of this reload
> must not extend past main insn. */ && rld[i].when_needed !=
> RELOAD_FOR_OUTPUT_ADDRESS && rld[i].when_needed !=
> RELOAD_FOR_OUTADDR_ADDRESS && rld[i].when_needed != RELOAD_OTHER &&
> (CLASS_MAX_NREGS (rld[i].class, rld[i].inmode) == CLASS_MAX_NREGS
> (rld[output_reload].class, rld[output_reload].outmode)) && rld
> [i].inc == 0 && rld[i].reg_rtx == 0 #ifdef SECONDARY_MEMORY_NEEDED /
> * Don't combine two reloads with different secondary memory
> locations. */ && (secondary_memlocs_elim[(int) rld
> [output_reload].outmode][rld[i].opnum] == 0 ||
> secondary_memlocs_elim[(int) rld[output_reload].outmode][rld
> [output_reload].opnum] == 0 || rtx_equal_p (secondary_memlocs_elim
> [(int) rld[output_reload].outmode][rld[i].opnum],
More information about the Gcc
mailing list