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