This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

reload.c as a bugzilla quip


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],


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]