| /* 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, 2004 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, 59 Temple Place - Suite 330, Boston, MA |
| 02111-1307, USA. */ |
| |
| /* This file contains subroutines used only from the file reload1.c. |
| It knows how to scan one insn for operands and values |
| that need to be copied into registers to make valid code. |
| It also finds other operands and values which are valid |
| but for which equivalent values in registers exist and |
| ought to be used instead. |
| |
| Before processing the first insn of the function, call `init_reload'. |
| |
| To scan an insn, call `find_reloads'. This does two things: |
| 1. sets up tables describing which values must be reloaded |
| for this insn, and what kind of hard regs they must be reloaded into; |
| 2. optionally record the locations where those values appear in |
| the data, so they can be replaced properly later. |
| This is done only if the second arg to `find_reloads' is nonzero. |
| |
| The third arg to `find_reloads' specifies the number of levels |
| of indirect addressing supported by the machine. If it is zero, |
| indirect addressing is not valid. If it is one, (MEM (REG n)) |
| is valid even if (REG n) did not get a hard register; if it is two, |
| (MEM (MEM (REG n))) is also valid even if (REG n) did not get a |
| hard register, and similarly for higher values. |
| |
| Then you must choose the hard regs to reload those pseudo regs into, |
| and generate appropriate load insns before this insn and perhaps |
| also store insns after this insn. Set up the array `reload_reg_rtx' |
| to contain the REG rtx's for the registers you used. In some |
| cases `find_reloads' will return a nonzero value in `reload_reg_rtx' |
| for certain reloads. Then that tells you which register to use, |
| so you do not need to allocate one. But you still do need to add extra |
| instructions to copy the value into and out of that register. |
| |
| Finally you must call `subst_reloads' to substitute the reload reg rtx's |
| into the locations already recorded. |
| |
| NOTE SIDE EFFECTS: |
| |
| find_reloads can alter the operands of the instruction it is called on. |
| |
| 1. Two operands of any sort may be interchanged, if they are in a |
| commutative instruction. |
| This happens only if find_reloads thinks the instruction will compile |
| better that way. |
| |
| 2. Pseudo-registers that are equivalent to constants are replaced |
| with those constants if they are not in hard registers. |
| |
| 1 happens every time find_reloads is called. |
| 2 happens only when REPLACE is 1, which is only 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 "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 "hard-reg-set.h" |
| #include "flags.h" |
| #include "real.h" |
| #include "output.h" |
| #include "function.h" |
| #include "toplev.h" |
| |
| #ifndef REGISTER_MOVE_COST |
| #define REGISTER_MOVE_COST(m, x, y) 2 |
| #endif |
| |
| #ifndef REGNO_MODE_OK_FOR_BASE_P |
| #define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO) |
| #endif |
| |
| #ifndef REG_MODE_OK_FOR_BASE_P |
| #define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO) |
| #endif |
| |
| /* 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]; |
| #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 && (GET_CODE (x) == REG \ |
| ? GET_CODE (y) == REG && 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))) |
| |
| #ifdef HAVE_SECONDARY_RELOADS |
| static int push_secondary_reload PARAMS ((int, rtx, int, int, enum reg_class, |
| enum machine_mode, enum reload_type, |
| enum insn_code *)); |
| #endif |
| static enum reg_class find_valid_class PARAMS ((enum machine_mode, int, |
| unsigned int)); |
| static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode, int)); |
| static int can_reload_into PARAMS ((rtx, int, enum machine_mode)); |
| static void push_replacement PARAMS ((rtx *, int, enum machine_mode)); |
| static void dup_replacements PARAMS ((rtx *, rtx *)); |
| static void combine_reloads PARAMS ((void)); |
| static int find_reusable_reload PARAMS ((rtx *, rtx, enum reg_class, |
| enum reload_type, int, int)); |
| static rtx find_dummy_reload PARAMS ((rtx, rtx, rtx *, rtx *, |
| enum machine_mode, enum machine_mode, |
| enum reg_class, int, int)); |
| static int hard_reg_set_here_p PARAMS ((unsigned int, unsigned int, rtx)); |
| static struct decomposition decompose PARAMS ((rtx)); |
| static int immune_p PARAMS ((rtx, rtx, struct decomposition)); |
| static int alternative_allows_memconst PARAMS ((const char *, int)); |
| static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int, |
| int, rtx, int *)); |
| static rtx make_memloc PARAMS ((rtx, int)); |
| static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *)); |
| static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *, |
| int, enum reload_type, int, rtx)); |
| static rtx subst_reg_equivs PARAMS ((rtx, rtx)); |
| static rtx subst_indexed_address PARAMS ((rtx)); |
| static void update_auto_inc_notes PARAMS ((rtx, int, int)); |
| static int find_reloads_address_1 PARAMS ((enum machine_mode, rtx, int, rtx *, |
| int, enum reload_type,int, rtx)); |
| static void find_reloads_address_part PARAMS ((rtx, rtx *, enum reg_class, |
| enum machine_mode, int, |
| enum reload_type, int)); |
| static rtx find_reloads_subreg_address PARAMS ((rtx, int, int, |
| enum reload_type, int, rtx)); |
| static void copy_replacements_1 PARAMS ((rtx *, rtx *, int)); |
| static int find_inc_amount PARAMS ((rtx, rtx)); |
| |
| #ifdef HAVE_SECONDARY_RELOADS |
| |
| /* 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 (in_p, x, opnum, optional, reload_class, reload_mode, |
| type, picode) |
| 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; |
| { |
| enum reg_class class = NO_REGS; |
| enum machine_mode mode = reload_mode; |
| enum insn_code icode = CODE_FOR_nothing; |
| enum reg_class t_class = NO_REGS; |
| enum machine_mode t_mode = VOIDmode; |
| enum insn_code t_icode = CODE_FOR_nothing; |
| enum reload_type secondary_type; |
| int s_reload, t_reload = -1; |
| |
| 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 (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER |
| && reg_equiv_mem[REGNO (x)] != 0) |
| x = reg_equiv_mem[REGNO (x)]; |
| |
| #ifdef SECONDARY_INPUT_RELOAD_CLASS |
| if (in_p) |
| class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x); |
| #endif |
| |
| #ifdef SECONDARY_OUTPUT_RELOAD_CLASS |
| if (! in_p) |
| class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x); |
| #endif |
| |
| /* If we don't need any secondary registers, done. */ |
| if (class == NO_REGS) |
| return -1; |
| |
| /* Get a possible insn to use. If the predicate doesn't accept X, don't |
| use the insn. */ |
| |
| icode = (in_p ? reload_in_optab[(int) reload_mode] |
| : reload_out_optab[(int) reload_mode]); |
| |
| if (icode != CODE_FOR_nothing |
| && insn_data[(int) icode].operand[in_p].predicate |
| && (! (insn_data[(int) icode].operand[in_p].predicate) (x, reload_mode))) |
| icode = CODE_FOR_nothing; |
| |
| /* If we will be using an insn, see if it can directly handle the reload |
| register we will be using. If it can, the secondary reload is for a |
| scratch register. If it can't, we will use the secondary reload for |
| an intermediate register and require a tertiary reload for the scratch |
| register. */ |
| |
| if (icode != CODE_FOR_nothing) |
| { |
| /* If IN_P is 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. */ |
| |
| enum reg_class insn_class; |
| |
| if (insn_data[(int) icode].operand[!in_p].constraint[0] == 0) |
| insn_class = ALL_REGS; |
| else |
| { |
| char insn_letter |
| = insn_data[(int) icode].operand[!in_p].constraint[in_p]; |
| insn_class |
| = (insn_letter == 'r' ? GENERAL_REGS |
| : REG_CLASS_FROM_LETTER ((unsigned char) insn_letter)); |
| |
| if (insn_class == NO_REGS) |
| abort (); |
| if (in_p |
| && insn_data[(int) icode].operand[!in_p].constraint[0] != '=') |
| abort (); |
| } |
| |
| /* The scratch register's constraint must start with "=&". */ |
| if (insn_data[(int) icode].operand[2].constraint[0] != '=' |
| || insn_data[(int) icode].operand[2].constraint[1] != '&') |
| abort (); |
| |
| if (reg_class_subset_p (reload_class, insn_class)) |
| mode = insn_data[(int) icode].operand[2].mode; |
| else |
| { |
| char t_letter = insn_data[(int) icode].operand[2].constraint[2]; |
| class = insn_class; |
| t_mode = insn_data[(int) icode].operand[2].mode; |
| t_class = (t_letter == 'r' ? GENERAL_REGS |
| : REG_CLASS_FROM_LETTER ((unsigned char) t_letter)); |
| t_icode = icode; |
| icode = CODE_FOR_nothing; |
| } |
| } |
| |
| /* 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. */ |
| |
| if (in_p && class == reload_class && icode == CODE_FOR_nothing |
| && t_icode == CODE_FOR_nothing) |
| abort (); |
| |
| /* If we need a tertiary reload, see if we have one we can reuse or else |
| make a new one. */ |
| |
| if (t_class != NO_REGS) |
| { |
| for (t_reload = 0; t_reload < n_reloads; t_reload++) |
| if (rld[t_reload].secondary_p |
| && (reg_class_subset_p (t_class, rld[t_reload].class) |
| || reg_class_subset_p (rld[t_reload].class, t_class)) |
| && ((in_p && rld[t_reload].inmode == t_mode) |
| || (! in_p && rld[t_reload].outmode == t_mode)) |
| && ((in_p && (rld[t_reload].secondary_in_icode |
| == CODE_FOR_nothing)) |
| || (! in_p &&(rld[t_reload].secondary_out_icode |
| == CODE_FOR_nothing))) |
| && (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES) |
| && MERGABLE_RELOADS (secondary_type, |
| rld[t_reload].when_needed, |
| opnum, rld[t_reload].opnum)) |
| { |
| if (in_p) |
| rld[t_reload].inmode = t_mode; |
| if (! in_p) |
| rld[t_reload].outmode = t_mode; |
| |
| if (reg_class_subset_p (t_class, rld[t_reload].class)) |
| rld[t_reload].class = t_class; |
| |
| rld[t_reload].opnum = MIN (rld[t_reload].opnum, opnum); |
| rld[t_reload].optional &= optional; |
| rld[t_reload].secondary_p = 1; |
| if (MERGE_TO_OTHER (secondary_type, rld[t_reload].when_needed, |
| opnum, rld[t_reload].opnum)) |
| rld[t_reload].when_needed = RELOAD_OTHER; |
| } |
| |
| if (t_reload == n_reloads) |
| { |
| /* We need to make a new tertiary reload for this register class. */ |
| rld[t_reload].in = rld[t_reload].out = 0; |
| rld[t_reload].class = t_class; |
| rld[t_reload].inmode = in_p ? t_mode : VOIDmode; |
| rld[t_reload].outmode = ! in_p ? t_mode : VOIDmode; |
| rld[t_reload].reg_rtx = 0; |
| rld[t_reload].optional = optional; |
| rld[t_reload].inc = 0; |
| /* Maybe we could combine these, but it seems too tricky. */ |
| rld[t_reload].nocombine = 1; |
| rld[t_reload].in_reg = 0; |
| rld[t_reload].out_reg = 0; |
| rld[t_reload].opnum = opnum; |
| rld[t_reload].when_needed = secondary_type; |
| rld[t_reload].secondary_in_reload = -1; |
| rld[t_reload].secondary_out_reload = -1; |
| rld[t_reload].secondary_in_icode = CODE_FOR_nothing; |
| rld[t_reload].secondary_out_icode = CODE_FOR_nothing; |
| rld[t_reload].secondary_p = 1; |
| |
| n_reloads++; |
| } |
| } |
| |
| /* 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)) |
| && (reg_class_size[(int) class] == 1 || 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; |
| } |
| #endif /* HAVE_SECONDARY_RELOADS */ |
| |
| #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 (x, mode, opnum, type) |
| 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; |
| return loc; |
| } |
| |
| /* Clear any secondary memory locations we've made. */ |
| |
| void |
| clear_secondary_mem () |
| { |
| memset ((char *) secondary_memlocs, 0, sizeof secondary_memlocs); |
| } |
| #endif /* SECONDARY_MEMORY_NEEDED */ |
| |
| /* Find the largest class for which every register number plus N is valid in |
| M1 (if in range) and is cheap to move into REGNO. |
| Abort if no such class exists. */ |
| |
| static enum reg_class |
| find_valid_class (m1, n, dest_regno) |
| enum machine_mode m1 ATTRIBUTE_UNUSED; |
| int n; |
| unsigned int dest_regno; |
| { |
| int best_cost = -1; |
| int class; |
| int regno; |
| enum reg_class best_class = NO_REGS; |
| enum reg_class dest_class = REGNO_REG_CLASS (dest_regno); |
| unsigned int best_size = 0; |
| int cost; |
| |
| for (class = 1; class < N_REG_CLASSES; class++) |
| { |
| int bad = 0; |
| for (regno = 0; regno < FIRST_PSEUDO_REGISTER && ! bad; regno++) |
| if (TEST_HARD_REG_BIT (reg_class_contents[class], regno) |
| && TEST_HARD_REG_BIT (reg_class_contents[class], regno + n) |
| && ! HARD_REGNO_MODE_OK (regno + n, m1)) |
| bad = 1; |
| |
| if (bad) |
| continue; |
| cost = REGISTER_MOVE_COST (m1, 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 (m1, class, dest_class); |
| } |
| } |
| |
| if (best_size == 0) |
| abort (); |
| |
| 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 (p_in, out, class, type, opnum, dont_share) |
| rtx *p_in, out; |
| enum reg_class class; |
| enum reload_type type; |
| int opnum, 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)) |
| && (reg_class_size[(int) class] == 1 || 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 |
| && ((GET_CODE (in) == REG |
| && GET_RTX_CLASS (GET_CODE (rld[i].in)) == 'a' |
| && MATCHES (XEXP (rld[i].in, 0), in)) |
| || (GET_CODE (rld[i].in) == REG |
| && GET_RTX_CLASS (GET_CODE (in)) == 'a' |
| && MATCHES (XEXP (in, 0), rld[i].in))) |
| && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out)) |
| && (reg_class_size[(int) class] == 1 || 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 (GET_CODE (in) == REG) |
| *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 (x, mode, output) |
| 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 (GET_CODE (inner) != REG |
| || REGNO (inner) >= FIRST_PSEUDO_REGISTER) |
| return 0; |
| |
| if (!subreg_offset_representable_p |
| (REGNO (SUBREG_REG (x)), |
| GET_MODE (SUBREG_REG (x)), |
| SUBREG_BYTE (x), |
| GET_MODE (x))) |
| return 1; |
| |
| /* 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 (in, regno, mode) |
| 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 (GET_CODE (in) == REG) |
| 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 (GET_CODE (in) == MEM) |
| 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 (in, out, inloc, outloc, class, |
| inmode, outmode, strict_low, optional, opnum, type) |
| rtx in, out; |
| rtx *inloc, *outloc; |
| enum reg_class class; |
| enum machine_mode inmode, 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 && GET_CODE (in) == REG) |
| { |
| 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 && GET_CODE (out) == REG) |
| { |
| 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 && GET_CODE (in) == MEM && 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 |
| || (((GET_CODE (SUBREG_REG (in)) == REG |
| && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER) |
| || GET_CODE (SUBREG_REG (in)) == MEM) |
| && ((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))) != NIL) |
| #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 |
| )) |
| || (GET_CODE (SUBREG_REG (in)) == REG |
| && 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))) |
| #ifdef SECONDARY_INPUT_RELOAD_CLASS |
| || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS |
| && (SECONDARY_INPUT_RELOAD_CLASS (class, |
| GET_MODE (SUBREG_REG (in)), |
| SUBREG_REG (in)) |
| == NO_REGS)) |
| #endif |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| || (GET_CODE (SUBREG_REG (in)) == REG |
| && 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 (GET_CODE (in) == MEM) |
| /* This is supposed to happen only for paradoxical subregs made by |
| combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */ |
| if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode)) |
| abort (); |
| #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 (GET_CODE (SUBREG_REG (in)) == REG) |
| in_class |
| = find_valid_class (inmode, |
| 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 |
| || (((GET_CODE (SUBREG_REG (out)) == REG |
| && REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER) |
| || GET_CODE (SUBREG_REG (out)) == MEM) |
| && ((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 |
| )) |
| || (GET_CODE (SUBREG_REG (out)) == REG |
| && 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))) |
| #ifdef SECONDARY_OUTPUT_RELOAD_CLASS |
| || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS |
| && (SECONDARY_OUTPUT_RELOAD_CLASS (class, |
| GET_MODE (SUBREG_REG (out)), |
| SUBREG_REG (out)) |
| == NO_REGS)) |
| #endif |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| || (GET_CODE (SUBREG_REG (out)) == REG |
| && 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) |
| if (GET_CODE (out) == MEM |
| && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode)) |
| abort (); |
| #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, |
| 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 && GET_CODE (out) == MEM |
| && (GET_CODE (in) == REG || GET_CODE (in) == MEM) |
| && 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 && GET_CODE (SUBREG_REG (in)) == REG |
| && 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 |
| && GET_CODE (SUBREG_REG (out)) == REG |
| && 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. */ |
| if (in != 0) |
| class = PREFERRED_RELOAD_CLASS (in, class); |
| |
| /* Output reloads may need analogous treatment, different in detail. */ |
| #ifdef PREFERRED_OUTPUT_RELOAD_CLASS |
| if (out != 0) |
| class = PREFERRED_OUTPUT_RELOAD_CLASS (out, class); |
| #endif |
| |
| /* 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'"); |
| class = ALL_REGS; |
| } |
| } |
| |
| /* 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. */ |
| if (class == NO_REGS |
| && (optional == 0 || type != RELOAD_FOR_OUTPUT)) |
| abort (); |
| |
| 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. */ |
| |
| #ifdef SECONDARY_INPUT_RELOAD_CLASS |
| if (in != 0) |
| secondary_in_reload |
| = push_secondary_reload (1, in, opnum, optional, class, inmode, type, |
| &secondary_in_icode); |
| #endif |
| |
| #ifdef SECONDARY_OUTPUT_RELOAD_CLASS |
| if (out != 0 && GET_CODE (out) != SCRATCH) |
| secondary_out_reload |
| = push_secondary_reload (0, out, opnum, optional, class, outmode, |
| type, &secondary_out_icode); |
| #endif |
| |
| /* 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 && (GET_CODE (in) == REG || GET_CODE (in) == SUBREG) |
| && 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 && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG) |
| && 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. */ |
| if (rld[i].inc == 0) |
| abort (); |
| } |
| #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 |
| && (GET_CODE (in) == REG || 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) |
| { |
| 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 |
| && GET_CODE (XEXP (note, 0)) == REG |
| && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER |
| && reg_mentioned_p (XEXP (note, 0), in) |
| && ! 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 (loc, reloadnum, mode) |
| 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 (dup_loc, orig_loc) |
| 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 (to, from) |
| int to, 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 (in_rtx) |
| 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 () |
| { |
| 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], |
| secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum])) |
| #endif |
| && (SMALL_REGISTER_CLASSES |
| ? (rld[i].class == rld[output_reload].class) |
| : (reg_class_subset_p (rld[i].class, |
| rld[output_reload].class) |
| || reg_class_subset_p (rld[output_reload].class, |
| rld[i].class))) |
| && (MATCHES (rld[i].in, rld[output_reload].out) |
| /* Args reversed because the first arg seems to be |
| the one that we imagine being modified |
| while the second is the one that might be affected. */ |
| || (! reg_overlap_mentioned_for_reload_p (rld[output_reload].out, |
| rld[i].in) |
| /* However, if the input is a register that appears inside |
| the output, then we also can't share. |
| Imagine (set (mem (reg 69)) (plus (reg 69) ...)). |
| If the same reload reg is used for both reg 69 and the |
| result to be stored in memory, then that result |
| will clobber the address of the memory ref. */ |
| && ! (GET_CODE (rld[i].in) == REG |
| && reg_overlap_mentioned_for_reload_p (rld[i].in, |
| rld[output_reload].out)))) |
| && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode, |
| rld[i].when_needed != RELOAD_FOR_INPUT) |
| && (reg_class_size[(int) rld[i].class] |
| || SMALL_REGISTER_CLASSES) |
| /* We will allow making things slightly worse by combining an |
| input and an output, but no worse than that. */ |
| && (rld[i].when_needed == RELOAD_FOR_INPUT |
| || rld[i].when_needed == RELOAD_FOR_OUTPUT)) |
| { |
| int j; |
| |
| /* We have found a reload to combine with! */ |
| rld[i].out = rld[output_reload].out; |
| rld[i].out_reg = rld[output_reload].out_reg; |
| rld[i].outmode = rld[output_reload].outmode; |
| /* Mark the old output reload as inoperative. */ |
| rld[output_reload].out = 0; |
| /* The combined reload is needed for the entire insn. */ |
| rld[i].when_needed = RELOAD_OTHER; |
| /* If the output reload had a secondary reload, copy it. */ |
| if (rld[output_reload].secondary_out_reload != -1) |
| { |
| rld[i].secondary_out_reload |
| = rld[output_reload].secondary_out_reload; |
| rld[i].secondary_out_icode |
| = rld[output_reload].secondary_out_icode; |
| } |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* Copy any secondary MEM. */ |
| if (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] != 0) |
| secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum] |
| = secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum]; |
| #endif |
| /* If required, minimize the register class. */ |
| if (reg_class_subset_p (rld[output_reload].class, |
| rld[i].class)) |
| rld[i].class = rld[output_reload].class; |
| |
| /* Transfer all replacements from the old reload to the combined. */ |
| for (j = 0; j < n_replacements; j++) |
| if (replacements[j].what == output_reload) |
| replacements[j].what = i; |
| |
| return; |
| } |
| |
| /* If this insn has only one operand that is modified or written (assumed |
| to be the first), it must be the one corresponding to this reload. It |
| is safe to use anything that dies in this insn for that output provided |
| that it does not occur in the output (we already know it isn't an |
| earlyclobber. If this is an asm insn, give up. */ |
| |
| if (INSN_CODE (this_insn) == -1) |
| return; |
| |
| for (i = 1; i < insn_data[INSN_CODE (this_insn)].n_operands; i++) |
| if (insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '=' |
| || insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '+') |
| return; |
| |
| /* See if some hard register that dies in this insn and is not used in |
| the output is the right class. Only works if the register we pick |
| up can fully hold our output reload. */ |
| for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1)) |
| if (REG_NOTE_KIND (note) == REG_DEAD |
| && GET_CODE (XEXP (note, 0)) == REG |
| && ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0), |
| rld[output_reload].out) |
| && REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER |
| && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), rld[output_reload].outmode) |
| && TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].class], |
| REGNO (XEXP (note, 0))) |
| && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), rld[output_reload].outmode) |
| <= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0)))) |
| /* Ensure that a secondary or tertiary reload for this output |
| won't want this register. */ |
| && ((secondary_out = rld[output_reload].secondary_out_reload) == -1 |
| || (! (TEST_HARD_REG_BIT |
| (reg_class_contents[(int) rld[secondary_out].class], |
| REGNO (XEXP (note, 0)))) |
| && ((secondary_out = rld[secondary_out].secondary_out_reload) == -1 |
| || ! (TEST_HARD_REG_BIT |
| (reg_class_contents[(int) rld[secondary_out].class], |
| REGNO (XEXP (note, 0))))))) |
| && ! fixed_regs[REGNO (XEXP (note, 0))]) |
| { |
| rld[output_reload].reg_rtx |
| = gen_rtx_REG (rld[output_reload].outmode, |
| REGNO (XEXP (note, 0))); |
| return; |
| } |
| } |
| |
| /* Try to find a reload register for an in-out reload (expressions IN and OUT). |
| See if one of IN and OUT is a register that may be used; |
| this is desirable since a spill-register won't be needed. |
| If so, return the register rtx that proves acceptable. |
| |
| INLOC and OUTLOC are locations where IN and OUT appear in the insn. |
| CLASS is the register class required for the reload. |
| |
| If FOR_REAL is >= 0, it is the number of the reload, |
| and in some cases when it can be discovered that OUT doesn't need |
| to be computed, clear out rld[FOR_REAL].out. |
| |
| If FOR_REAL is -1, this should not be done, because this call |
| is just to see if a register can be found, not to find and install it. |
| |
| EARLYCLOBBER is nonzero if OUT is an earlyclobber operand. This |
| puts an additional constraint on being able to use IN for OUT since |
| IN must not appear elsewhere in the insn (it is assumed that IN itself |
| is safe from the earlyclobber). */ |
| |
| static rtx |
| find_dummy_reload (real_in, real_out, inloc, outloc, |
| inmode, outmode, class, for_real, earlyclobber) |
| rtx real_in, real_out; |
| rtx *inloc, *outloc; |
| enum machine_mode inmode, outmode; |
| enum reg_class class; |
| int for_real; |
| int earlyclobber; |
| { |
| rtx in = real_in; |
| rtx out = real_out; |
| int in_offset = 0; |
| int out_offset = 0; |
| rtx value = 0; |
| |
| /* If operands exceed a word, we can't use either of them |
| unless they have the same size. */ |
| if (GET_MODE_SIZE (outmode) != GET_MODE_SIZE (inmode) |
| && (GET_MODE_SIZE (outmode) > UNITS_PER_WORD |
| || GET_MODE_SIZE (inmode) > UNITS_PER_WORD)) |
| return 0; |
| |
| /* Note that {in,out}_offset are needed only when 'in' or 'out' |
| respectively refers to a hard register. */ |
| |
| /* Find the inside of any subregs. */ |
| while (GET_CODE (out) == SUBREG) |
| { |
| if (GET_CODE (SUBREG_REG (out)) == REG |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER) |
| out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)), |
| GET_MODE (SUBREG_REG (out)), |
| SUBREG_BYTE (out), |
| GET_MODE (out)); |
| out = SUBREG_REG (out); |
| } |
| while (GET_CODE (in) == SUBREG) |
| { |
| if (GET_CODE (SUBREG_REG (in)) == REG |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER) |
| in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)), |
| GET_MODE (SUBREG_REG (in)), |
| SUBREG_BYTE (in), |
| GET_MODE (in)); |
| in = SUBREG_REG (in); |
| } |
| |
| /* Narrow down the reg class, the same way push_reload will; |
| otherwise we might find a dummy now, but push_reload won't. */ |
| class = PREFERRED_RELOAD_CLASS (in, class); |
| |
| /* See if OUT will do. */ |
| if (GET_CODE (out) == REG |
| && REGNO (out) < FIRST_PSEUDO_REGISTER) |
| { |
| unsigned int regno = REGNO (out) + out_offset; |
| unsigned int nwords = HARD_REGNO_NREGS (regno, outmode); |
| rtx saved_rtx; |
| |
| /* When we consider whether the insn uses OUT, |
| ignore references within IN. They don't prevent us |
| from copying IN into OUT, because those refs would |
| move into the insn that reloads IN. |
| |
| However, we only ignore IN in its role as this reload. |
| If the insn uses IN elsewhere and it contains OUT, |
| that counts. We can't be sure it's the "same" operand |
| so it might not go through this reload. */ |
| saved_rtx = *inloc; |
| *inloc = const0_rtx; |
| |
| if (regno < FIRST_PSEUDO_REGISTER |
| && HARD_REGNO_MODE_OK (regno, outmode) |
| && ! refers_to_regno_for_reload_p (regno, regno + nwords, |
| PATTERN (this_insn), outloc)) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < nwords; i++) |
| if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], |
| regno + i)) |
| break; |
| |
| if (i == nwords) |
| { |
| if (GET_CODE (real_out) == REG) |
| value = real_out; |
| else |
| value = gen_rtx_REG (outmode, regno); |
| } |
| } |
| |
| *inloc = saved_rtx; |
| } |
| |
| /* Consider using IN if OUT was not acceptable |
| or if OUT dies in this insn (like the quotient in a divmod insn). |
| We can't use IN unless it is dies in this insn, |
| which means we must know accurately which hard regs are live. |
| Also, the result can't go in IN if IN is used within OUT, |
| or if OUT is an earlyclobber and IN appears elsewhere in the insn. */ |
| if (hard_regs_live_known |
| && GET_CODE (in) == REG |
| && REGNO (in) < FIRST_PSEUDO_REGISTER |
| && (value == 0 |
| || find_reg_note (this_insn, REG_UNUSED, real_out)) |
| && find_reg_note (this_insn, REG_DEAD, real_in) |
| && !fixed_regs[REGNO (in)] |
| && HARD_REGNO_MODE_OK (REGNO (in), |
| /* The only case where out and real_out might |
| have different modes is where real_out |
| is a subreg, and in that case, out |
| has a real mode. */ |
| (GET_MODE (out) != VOIDmode |
| ? GET_MODE (out) : outmode))) |
| { |
| unsigned int regno = REGNO (in) + in_offset; |
| unsigned int nwords = HARD_REGNO_NREGS (regno, inmode); |
| |
| if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, (rtx*) 0) |
| && ! hard_reg_set_here_p (regno, regno + nwords, |
| PATTERN (this_insn)) |
| && (! earlyclobber |
| || ! refers_to_regno_for_reload_p (regno, regno + nwords, |
| PATTERN (this_insn), inloc))) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < nwords; i++) |
| if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], |
| regno + i)) |
| break; |
| |
| if (i == nwords) |
| { |
| /* If we were going to use OUT as the reload reg |
| and changed our mind, it means OUT is a dummy that |
| dies here. So don't bother copying value to it. */ |
| if (for_real >= 0 && value == real_out) |
| rld[for_real].out = 0; |
| if (GET_CODE (real_in) == REG) |
| value = real_in; |
| else |
| value = gen_rtx_REG (inmode, regno); |
| } |
| } |
| } |
| |
| return value; |
| } |
| |
| /* This page contains subroutines used mainly for determining |
| whether the IN or an OUT of a reload can serve as the |
| reload register. */ |
| |
| /* Return 1 if X is an operand of an insn that is being earlyclobbered. */ |
| |
| int |
| earlyclobber_operand_p (x) |
| rtx x; |
| { |
| int i; |
| |
| for (i = 0; i < n_earlyclobbers; i++) |
| if (reload_earlyclobbers[i] == x) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* Return 1 if expression X alters a hard reg in the range |
| from BEG_REGNO (inclusive) to END_REGNO (exclusive), |
| either explicitly or in the guise of a pseudo-reg allocated to REGNO. |
| X should be the body of an instruction. */ |
| |
| static int |
| hard_reg_set_here_p (beg_regno, end_regno, x) |
| unsigned int beg_regno, end_regno; |
| rtx x; |
| { |
| if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) |
| { |
| rtx op0 = SET_DEST (x); |
| |
| while (GET_CODE (op0) == SUBREG) |
| op0 = SUBREG_REG (op0); |
| if (GET_CODE (op0) == REG) |
| { |
| unsigned int r = REGNO (op0); |
| |
| /* See if this reg overlaps range under consideration. */ |
| if (r < end_regno |
| && r + HARD_REGNO_NREGS (r, GET_MODE (op0)) > beg_regno) |
| return 1; |
| } |
| } |
| else if (GET_CODE (x) == PARALLEL) |
| { |
| int i = XVECLEN (x, 0) - 1; |
| |
| for (; i >= 0; i--) |
| if (hard_reg_set_here_p (beg_regno, end_regno, XVECEXP (x, 0, i))) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* Return 1 if ADDR is a valid memory address for mode MODE, |
| and check that each pseudo reg has the proper kind of |
| hard reg. */ |
| |
| int |
| strict_memory_address_p (mode, addr) |
| enum machine_mode mode ATTRIBUTE_UNUSED; |
| rtx addr; |
| { |
| GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); |
| return 0; |
| |
| win: |
| return 1; |
| } |
| |
| /* Like rtx_equal_p except that it allows a REG and a SUBREG to match |
| if they are the same hard reg, and has special hacks for |
| autoincrement and autodecrement. |
| This is specifically intended for find_reloads to use |
| in determining whether two operands match. |
| X is the operand whose number is the lower of the two. |
| |
| The value is 2 if Y contains a pre-increment that matches |
| a non-incrementing address in X. */ |
| |
| /* ??? To be completely correct, we should arrange to pass |
| for X the output operand and for Y the input operand. |
| For now, we assume that the output operand has the lower number |
| because that is natural in (SET output (... input ...)). */ |
| |
| int |
| operands_match_p (x, y) |
| rtx x, y; |
| { |
| int i; |
| RTX_CODE code = GET_CODE (x); |
| const char *fmt; |
| int success_2; |
| |
| if (x == y) |
| return 1; |
| if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)) |
| && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG |
| && GET_CODE (SUBREG_REG (y)) == REG))) |
| { |
| int j; |
| |
| if (code == SUBREG) |
| { |
| i = REGNO (SUBREG_REG (x)); |
| if (i >= FIRST_PSEUDO_REGISTER) |
| goto slow; |
| i += subreg_regno_offset (REGNO (SUBREG_REG (x)), |
| GET_MODE (SUBREG_REG (x)), |
| SUBREG_BYTE (x), |
| GET_MODE (x)); |
| } |
| else |
| i = REGNO (x); |
| |
| if (GET_CODE (y) == SUBREG) |
| { |
| j = REGNO (SUBREG_REG (y)); |
| if (j >= FIRST_PSEUDO_REGISTER) |
| goto slow; |
| j += subreg_regno_offset (REGNO (SUBREG_REG (y)), |
| GET_MODE (SUBREG_REG (y)), |
| SUBREG_BYTE (y), |
| GET_MODE (y)); |
| } |
| else |
| j = REGNO (y); |
| |
| /* On a WORDS_BIG_ENDIAN machine, point to the last register of a |
| multiple hard register group, so that for example (reg:DI 0) and |
| (reg:SI 1) will be considered the same register. */ |
| if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD |
| && i < FIRST_PSEUDO_REGISTER) |
| i += (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD) - 1; |
| if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD |
| && j < FIRST_PSEUDO_REGISTER) |
| j += (GET_MODE_SIZE (GET_MODE (y)) / UNITS_PER_WORD) - 1; |
| |
| return i == j; |
| } |
| /* If two operands must match, because they are really a single |
| operand of an assembler insn, then two postincrements are invalid |
| because the assembler insn would increment only once. |
| On the other hand, a postincrement matches ordinary indexing |
| if the postincrement is the output operand. */ |
| if (code == POST_DEC || code == POST_INC || code == POST_MODIFY) |
| return operands_match_p (XEXP (x, 0), y); |
| /* Two preincrements are invalid |
| because the assembler insn would increment only once. |
| On the other hand, a preincrement matches ordinary indexing |
| if the preincrement is the input operand. |
| In this case, return 2, since some callers need to do special |
| things when this happens. */ |
| if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC |
| || GET_CODE (y) == PRE_MODIFY) |
| return operands_match_p (x, XEXP (y, 0)) ? 2 : 0; |
| |
| slow: |
| |
| /* Now we have disposed of all the cases |
| in which different rtx codes can match. */ |
| if (code != GET_CODE (y)) |
| return 0; |
| if (code == LABEL_REF) |
| return XEXP (x, 0) == XEXP (y, 0); |
| if (code == SYMBOL_REF) |
| return XSTR (x, 0) == XSTR (y, 0); |
| |
| /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ |
| |
| if (GET_MODE (x) != GET_MODE (y)) |
| return 0; |
| |
| /* Compare the elements. If any pair of corresponding elements |
| fail to match, return 0 for the whole things. */ |
| |
| success_2 = 0; |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| { |
| int val, j; |
| switch (fmt[i]) |
| { |
| case 'w': |
| if (XWINT (x, i) != XWINT (y, i)) |
| return 0; |
| break; |
| |
| case 'i': |
| if (XINT (x, i) != XINT (y, i)) |
| return 0; |
| break; |
| |
| case 'e': |
| val = operands_match_p (XEXP (x, i), XEXP (y, i)); |
| if (val == 0) |
| return 0; |
| /* If any subexpression returns 2, |
| we should return 2 if we are successful. */ |
| if (val == 2) |
| success_2 = 1; |
| break; |
| |
| case '0': |
| break; |
| |
| case 'E': |
| if (XVECLEN (x, i) != XVECLEN (y, i)) |
| return 0; |
| for (j = XVECLEN (x, i) - 1; j >= 0; --j) |
| { |
| val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j)); |
| if (val == 0) |
| return 0; |
| if (val == 2) |
| success_2 = 1; |
| } |
| break; |
| |
| /* It is believed that rtx's at this level will never |
| contain anything but integers and other rtx's, |
| except for within LABEL_REFs and SYMBOL_REFs. */ |
| default: |
| abort (); |
| } |
| } |
| return 1 + success_2; |
| } |
| |
| /* Describe the range of registers or memory referenced by X. |
| If X is a register, set REG_FLAG and put the first register |
| number into START and the last plus one into END. |
| If X is a memory reference, put a base address into BASE |
| and a range of integer offsets into START and END. |
| If X is pushing on the stack, we can assume it causes no trouble, |
| so we set the SAFE field. */ |
| |
| static struct decomposition |
| decompose (x) |
| rtx x; |
| { |
| struct decomposition val; |
| int all_const = 0; |
| |
| val.reg_flag = 0; |
| val.safe = 0; |
| val.base = 0; |
| if (GET_CODE (x) == MEM) |
| { |
| rtx base = NULL_RTX, offset = 0; |
| rtx addr = XEXP (x, 0); |
| |
| if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC |
| || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) |
| { |
| val.base = XEXP (addr, 0); |
| val.start = -GET_MODE_SIZE (GET_MODE (x)); |
| val.end = GET_MODE_SIZE (GET_MODE (x)); |
| val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; |
| return val; |
| } |
| |
| if (GET_CODE (addr) == PRE_MODIFY || GET_CODE (addr) == POST_MODIFY) |
| { |
| if (GET_CODE (XEXP (addr, 1)) == PLUS |
| && XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0) |
| && CONSTANT_P (XEXP (XEXP (addr, 1), 1))) |
| { |
| val.base = XEXP (addr, 0); |
| val.start = -INTVAL (XEXP (XEXP (addr, 1), 1)); |
| val.end = INTVAL (XEXP (XEXP (addr, 1), 1)); |
| val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; |
| return val; |
| } |
| } |
| |
| if (GET_CODE (addr) == CONST) |
| { |
| addr = XEXP (addr, 0); |
| all_const = 1; |
| } |
| if (GET_CODE (addr) == PLUS) |
| { |
| if (CONSTANT_P (XEXP (addr, 0))) |
| { |
| base = XEXP (addr, 1); |
| offset = XEXP (addr, 0); |
| } |
| else if (CONSTANT_P (XEXP (addr, 1))) |
| { |
| base = XEXP (addr, 0); |
| offset = XEXP (addr, 1); |
| } |
| } |
| |
| if (offset == 0) |
| { |
| base = addr; |
| offset = const0_rtx; |
| } |
| if (GET_CODE (offset) == CONST) |
| offset = XEXP (offset, 0); |
| if (GET_CODE (offset) == PLUS) |
| { |
| if (GET_CODE (XEXP (offset, 0)) == CONST_INT) |
| { |
| base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1)); |
| offset = XEXP (offset, 0); |
| } |
| else if (GET_CODE (XEXP (offset, 1)) == CONST_INT) |
| { |
| base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0)); |
| offset = XEXP (offset, 1); |
| } |
| else |
| { |
| base = gen_rtx_PLUS (GET_MODE (base), base, offset); |
| offset = const0_rtx; |
| } |
| } |
| else if (GET_CODE (offset) != CONST_INT) |
| { |
| base = gen_rtx_PLUS (GET_MODE (base), base, offset); |
| offset = const0_rtx; |
| } |
| |
| if (all_const && GET_CODE (base) == PLUS) |
| base = gen_rtx_CONST (GET_MODE (base), base); |
| |
| if (GET_CODE (offset) != CONST_INT) |
| abort (); |
| |
| val.start = INTVAL (offset); |
| val.end = val.start + GET_MODE_SIZE (GET_MODE (x)); |
| val.base = base; |
| return val; |
| } |
| else if (GET_CODE (x) == REG) |
| { |
| val.reg_flag = 1; |
| val.start = true_regnum (x); |
| if (val.start < 0) |
| { |
| /* A pseudo with no hard reg. */ |
| val.start = REGNO (x); |
| val.end = val.start + 1; |
| } |
| else |
| /* A hard reg. */ |
| val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x)); |
| } |
| else if (GET_CODE (x) == SUBREG) |
| { |
| if (GET_CODE (SUBREG_REG (x)) != REG) |
| /* This could be more precise, but it's good enough. */ |
| return decompose (SUBREG_REG (x)); |
| val.reg_flag = 1; |
| val.start = true_regnum (x); |
| if (val.start < 0) |
| return decompose (SUBREG_REG (x)); |
| else |
| /* A hard reg. */ |
| val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x)); |
| } |
| else if (CONSTANT_P (x) |
| /* This hasn't been assigned yet, so it can't conflict yet. */ |
| || GET_CODE (x) == SCRATCH) |
| val.safe = 1; |
| else |
| abort (); |
| return val; |
| } |
| |
| /* Return 1 if altering Y will not modify the value of X. |
| Y is also described by YDATA, which should be decompose (Y). */ |
| |
| static int |
| immune_p (x, y, ydata) |
| rtx x, y; |
| struct decomposition ydata; |
| { |
| struct decomposition xdata; |
| |
| if (ydata.reg_flag) |
| return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, (rtx*) 0); |
| if (ydata.safe) |
| return 1; |
| |
| if (GET_CODE (y) != MEM) |
| abort (); |
| /* If Y is memory and X is not, Y can't affect X. */ |
| if (GET_CODE (x) != MEM) |
| return 1; |
| |
| xdata = decompose (x); |
| |
| if (! rtx_equal_p (xdata.base, ydata.base)) |
| { |
| /* If bases are distinct symbolic constants, there is no overlap. */ |
| if (CONSTANT_P (xdata.base) && CONSTANT_P (ydata.base)) |
| return 1; |
| /* Constants and stack slots never overlap. */ |
| if (CONSTANT_P (xdata.base) |
| && (ydata.base == frame_pointer_rtx |
| || ydata.base == hard_frame_pointer_rtx |
| || ydata.base == stack_pointer_rtx)) |
| return 1; |
| if (CONSTANT_P (ydata.base) |
| && (xdata.base == frame_pointer_rtx |
| || xdata.base == hard_frame_pointer_rtx |
| || xdata.base == stack_pointer_rtx)) |
| return 1; |
| /* If either base is variable, we don't know anything. */ |
| return 0; |
| } |
| |
| return (xdata.start >= ydata.end || ydata.start >= xdata.end); |
| } |
| |
| /* Similar, but calls decompose. */ |
| |
| int |
| safe_from_earlyclobber (op, clobber) |
| rtx op, clobber; |
| { |
| struct decomposition early_data; |
| |
| early_data = decompose (clobber); |
| return immune_p (op, clobber, early_data); |
| } |
| |
| /* Main entry point of this file: search the body of INSN |
| for values that need reloading and record them with push_reload. |
| REPLACE nonzero means record also where the values occur |
| so that subst_reloads can be used. |
| |
| IND_LEVELS says how many levels of indirection are supported by this |
| machine; a value of zero means that a memory reference is not a valid |
| memory address. |
| |
| LIVE_KNOWN says we have valid information about which hard |
| regs are live at each point in the program; this is true when |
| we are called from global_alloc but false when stupid register |
| allocation has been done. |
| |
| RELOAD_REG_P if nonzero is a vector indexed by hard reg number |
| which is nonnegative if the reg has been commandeered for reloading into. |
| It is copied into STATIC_RELOAD_REG_P and referenced from there |
| by various subroutines. |
| |
| Return TRUE if some operands need to be changed, because of swapping |
| commutative operands, reg_equiv_address substitution, or whatever. */ |
| |
| int |
| find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) |
| rtx insn; |
| int replace, ind_levels; |
| int live_known; |
| short *reload_reg_p; |
| { |
| int insn_code_number; |
| int i, j; |
| int noperands; |
| /* These start out as the constraints for the insn |
| and they are chewed up as we consider alternatives. */ |
| char *constraints[MAX_RECOG_OPERANDS]; |
| /* These are the preferred classes for an operand, or NO_REGS if it isn't |
| a register. */ |
| enum reg_class preferred_class[MAX_RECOG_OPERANDS]; |
| char pref_or_nothing[MAX_RECOG_OPERANDS]; |
| /* Nonzero for a MEM operand whose entire address needs a reload. */ |
| int address_reloaded[MAX_RECOG_OPERANDS]; |
| /* Nonzero for an address operand that needs to be completely reloaded. */ |
| int address_operand_reloaded[MAX_RECOG_OPERANDS]; |
| /* Value of enum reload_type to use for operand. */ |
| enum reload_type operand_type[MAX_RECOG_OPERANDS]; |
| /* Value of enum reload_type to use within address of operand. */ |
| enum reload_type address_type[MAX_RECOG_OPERANDS]; |
| /* Save the usage of each operand. */ |
| enum reload_usage { RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE } modified[MAX_RECOG_OPERANDS]; |
| int no_input_reloads = 0, no_output_reloads = 0; |
| int n_alternatives; |
| int this_alternative[MAX_RECOG_OPERANDS]; |
| char this_alternative_match_win[MAX_RECOG_OPERANDS]; |
| char this_alternative_win[MAX_RECOG_OPERANDS]; |
| char this_alternative_offmemok[MAX_RECOG_OPERANDS]; |
| char this_alternative_earlyclobber[MAX_RECOG_OPERANDS]; |
| int this_alternative_matches[MAX_RECOG_OPERANDS]; |
| int swapped; |
| int goal_alternative[MAX_RECOG_OPERANDS]; |
| int this_alternative_number; |
| int goal_alternative_number = 0; |
| int operand_reloadnum[MAX_RECOG_OPERANDS]; |
| int goal_alternative_matches[MAX_RECOG_OPERANDS]; |
| int goal_alternative_matched[MAX_RECOG_OPERANDS]; |
| char goal_alternative_match_win[MAX_RECOG_OPERANDS]; |
| char goal_alternative_win[MAX_RECOG_OPERANDS]; |
| char goal_alternative_offmemok[MAX_RECOG_OPERANDS]; |
| char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS]; |
| int goal_alternative_swapped; |
| int best; |
| int commutative; |
| char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS]; |
| rtx substed_operand[MAX_RECOG_OPERANDS]; |
| rtx body = PATTERN (insn); |
| rtx set = single_set (insn); |
| int goal_earlyclobber = 0, this_earlyclobber; |
| enum machine_mode operand_mode[MAX_RECOG_OPERANDS]; |
| int retval = 0; |
| |
| this_insn = insn; |
| n_reloads = 0; |
| n_replacements = 0; |
| n_earlyclobbers = 0; |
| replace_reloads = replace; |
| hard_regs_live_known = live_known; |
| static_reload_reg_p = reload_reg_p; |
| |
| /* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads; |
| neither are insns that SET cc0. Insns that use CC0 are not allowed |
| to have any input reloads. */ |
| if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN) |
| no_output_reloads = 1; |
| |
| #ifdef HAVE_cc0 |
| if (reg_referenced_p (cc0_rtx, PATTERN (insn))) |
| no_input_reloads = 1; |
| if (reg_set_p (cc0_rtx, PATTERN (insn))) |
| no_output_reloads = 1; |
| #endif |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* The eliminated forms of any secondary memory locations are per-insn, so |
| clear them out here. */ |
| |
| memset ((char *) secondary_memlocs_elim, 0, sizeof secondary_memlocs_elim); |
| #endif |
| |
| /* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it |
| is cheap to move between them. If it is not, there may not be an insn |
| to do the copy, so we may need a reload. */ |
| if (GET_CODE (body) == SET |
| && GET_CODE (SET_DEST (body)) == REG |
| && REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER |
| && GET_CODE (SET_SRC (body)) == REG |
| && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER |
| && REGISTER_MOVE_COST (GET_MODE (SET_SRC (body)), |
| REGNO_REG_CLASS (REGNO (SET_SRC (body))), |
| REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2) |
| return 0; |
| |
| extract_insn (insn); |
| |
| noperands = reload_n_operands = recog_data.n_operands; |
| n_alternatives = recog_data.n_alternatives; |
| |
| /* Just return "no reloads" if insn has no operands with constraints. */ |
| if (noperands == 0 || n_alternatives == 0) |
| return 0; |
| |
| insn_code_number = INSN_CODE (insn); |
| this_insn_is_asm = insn_code_number < 0; |
| |
| memcpy (operand_mode, recog_data.operand_mode, |
| noperands * sizeof (enum machine_mode)); |
| memcpy (constraints, recog_data.constraints, noperands * sizeof (char *)); |
| |
| commutative = -1; |
| |
| /* If we will need to know, later, whether some pair of operands |
| are the same, we must compare them now and save the result. |
| Reloading the base and index registers will clobber them |
| and afterward they will fail to match. */ |
| |
| for (i = 0; i < noperands; i++) |
| { |
| char *p; |
| int c; |
| |
| substed_operand[i] = recog_data.operand[i]; |
| p = constraints[i]; |
| |
| modified[i] = RELOAD_READ; |
| |
| /* Scan this operand's constraint to see if it is an output operand, |
| an in-out operand, is commutative, or should match another. */ |
| |
| while ((c = *p++)) |
| { |
| if (c == '=') |
| modified[i] = RELOAD_WRITE; |
| else if (c == '+') |
| modified[i] = RELOAD_READ_WRITE; |
| else if (c == '%') |
| { |
| /* The last operand should not be marked commutative. */ |
| if (i == noperands - 1) |
| abort (); |
| |
| /* We currently only support one commutative pair of |
| operands. Some existing asm code currently uses more |
| than one pair. Previously, that would usually work, |
| but sometimes it would crash the compiler. We |
| continue supporting that case as well as we can by |
| silently ignoring all but the first pair. In the |
| future we may handle it correctly. */ |
| if (commutative < 0) |
| commutative = i; |
| } |
| else if (ISDIGIT (c)) |
| { |
| c = strtoul (p - 1, &p, 10); |
| |
| operands_match[c][i] |
| = operands_match_p (recog_data.operand[c], |
| recog_data.operand[i]); |
| |
| /* An operand may not match itself. */ |
| if (c == i) |
| abort (); |
| |
| /* If C can be commuted with C+1, and C might need to match I, |
| then C+1 might also need to match I. */ |
| if (commutative >= 0) |
| { |
| if (c == commutative || c == commutative + 1) |
| { |
| int other = c + (c == commutative ? 1 : -1); |
| operands_match[other][i] |
| = operands_match_p (recog_data.operand[other], |
| recog_data.operand[i]); |
| } |
| if (i == commutative || i == commutative + 1) |
| { |
| int other = i + (i == commutative ? 1 : -1); |
| operands_match[c][other] |
| = operands_match_p (recog_data.operand[c], |
| recog_data.operand[other]); |
| } |
| /* Note that C is supposed to be less than I. |
| No need to consider altering both C and I because in |
| that case we would alter one into the other. */ |
| } |
| } |
| } |
| } |
| |
| /* Examine each operand that is a memory reference or memory address |
| and reload parts of the addresses into index registers. |
| Also here any references to pseudo regs that didn't get hard regs |
| but are equivalent to constants get replaced in the insn itself |
| with those constants. Nobody will ever see them again. |
| |
| Finally, set up the preferred classes of each operand. */ |
| |
| for (i = 0; i < noperands; i++) |
| { |
| RTX_CODE code = GET_CODE (recog_data.operand[i]); |
| |
| address_reloaded[i] = 0; |
| address_operand_reloaded[i] = 0; |
| operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT |
| : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT |
| : RELOAD_OTHER); |
| address_type[i] |
| = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT_ADDRESS |
| : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT_ADDRESS |
| : RELOAD_OTHER); |
| |
| if (*constraints[i] == 0) |
| /* Ignore things like match_operator operands. */ |
| ; |
| else if (constraints[i][0] == 'p' |
| || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0])) |
| { |
| address_operand_reloaded[i] |
| = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0, |
| recog_data.operand[i], |
| recog_data.operand_loc[i], |
| i, operand_type[i], ind_levels, insn); |
| |
| /* If we now have a simple operand where we used to have a |
| PLUS or MULT, re-recognize and try again. */ |
| if ((GET_RTX_CLASS (GET_CODE (*recog_data.operand_loc[i])) == 'o' |
| || GET_CODE (*recog_data.operand_loc[i]) == SUBREG) |
| && (GET_CODE (recog_data.operand[i]) == MULT |
| || GET_CODE (recog_data.operand[i]) == PLUS)) |
| { |
| INSN_CODE (insn) = -1; |
| retval = find_reloads (insn, replace, ind_levels, live_known, |
| reload_reg_p); |
| return retval; |
| } |
| |
| recog_data.operand[i] = *recog_data.operand_loc[i]; |
| substed_operand[i] = recog_data.operand[i]; |
| |
| /* Address operands are reloaded in their existing mode, |
| no matter what is specified in the machine description. */ |
| operand_mode[i] = GET_MODE (recog_data.operand[i]); |
| } |
| else if (code == MEM) |
| { |
| address_reloaded[i] |
| = find_reloads_address (GET_MODE (recog_data.operand[i]), |
| recog_data.operand_loc[i], |
| XEXP (recog_data.operand[i], 0), |
| &XEXP (recog_data.operand[i], 0), |
| i, address_type[i], ind_levels, insn); |
| recog_data.operand[i] = *recog_data.operand_loc[i]; |
| substed_operand[i] = recog_data.operand[i]; |
| } |
| else if (code == SUBREG) |
| { |
| rtx reg = SUBREG_REG (recog_data.operand[i]); |
| rtx op |
| = find_reloads_toplev (recog_data.operand[i], i, address_type[i], |
| ind_levels, |
| set != 0 |
| && &SET_DEST (set) == recog_data.operand_loc[i], |
| insn, |
| &address_reloaded[i]); |
| |
| /* If we made a MEM to load (a part of) the stackslot of a pseudo |
| that didn't get a hard register, emit a USE with a REG_EQUAL |
| note in front so that we might inherit a previous, possibly |
| wider reload. */ |
| |
| if (replace |
| && GET_CODE (op) == MEM |
| && GET_CODE (reg) == REG |
| && (GET_MODE_SIZE (GET_MODE (reg)) |
| >= GET_MODE_SIZE (GET_MODE (op)))) |
| set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg), |
| insn), |
| REG_EQUAL, reg_equiv_memory_loc[REGNO (reg)]); |
| |
| substed_operand[i] = recog_data.operand[i] = op; |
| } |
| else if (code == PLUS || GET_RTX_CLASS (code) == '1') |
| /* We can get a PLUS as an "operand" as a result of register |
| elimination. See eliminate_regs and gen_reload. We handle |
| a unary operator by reloading the operand. */ |
| substed_operand[i] = recog_data.operand[i] |
| = find_reloads_toplev (recog_data.operand[i], i, address_type[i], |
| ind_levels, 0, insn, |
| &address_reloaded[i]); |
| else if (code == REG) |
| { |
| /* This is equivalent to calling find_reloads_toplev. |
| The code is duplicated for speed. |
| When we find a pseudo always equivalent to a constant, |
| we replace it by the constant. We must be sure, however, |
| that we don't try to replace it in the insn in which it |
| is being set. */ |
| int regno = REGNO (recog_data.operand[i]); |
| if (reg_equiv_constant[regno] != 0 |
| && (set == 0 || &SET_DEST (set) != recog_data.operand_loc[i])) |
| { |
| /* Record the existing mode so that the check if constants are |
| allowed will work when operand_mode isn't specified. */ |
| |
| if (operand_mode[i] == VOIDmode) |
| operand_mode[i] = GET_MODE (recog_data.operand[i]); |
| |
| substed_operand[i] = recog_data.operand[i] |
| = reg_equiv_constant[regno]; |
| } |
| if (reg_equiv_memory_loc[regno] != 0 |
| && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)) |
| /* We need not give a valid is_set_dest argument since the case |
| of a constant equivalence was checked above. */ |
| substed_operand[i] = recog_data.operand[i] |
| = find_reloads_toplev (recog_data.operand[i], i, address_type[i], |
| ind_levels, 0, insn, |
| &address_reloaded[i]); |
| } |
| /* If the operand is still a register (we didn't replace it with an |
| equivalent), get the preferred class to reload it into. */ |
| code = GET_CODE (recog_data.operand[i]); |
| preferred_class[i] |
| = ((code == REG && REGNO (recog_data.operand[i]) |
| >= FIRST_PSEUDO_REGISTER) |
| ? reg_preferred_class (REGNO (recog_data.operand[i])) |
| : NO_REGS); |
| pref_or_nothing[i] |
| = (code == REG |
| && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER |
| && reg_alternate_class (REGNO (recog_data.operand[i])) == NO_REGS); |
| } |
| |
| /* If this is simply a copy from operand 1 to operand 0, merge the |
| preferred classes for the operands. */ |
| if (set != 0 && noperands >= 2 && recog_data.operand[0] == SET_DEST (set) |
| && recog_data.operand[1] == SET_SRC (set)) |
| { |
| preferred_class[0] = preferred_class[1] |
| = reg_class_subunion[(int) preferred_class[0]][(int) preferred_class[1]]; |
| pref_or_nothing[0] |= pref_or_nothing[1]; |
| pref_or_nothing[1] |= pref_or_nothing[0]; |
| } |
| |
| /* Now see what we need for pseudo-regs that didn't get hard regs |
| or got the wrong kind of hard reg. For this, we must consider |
| all the operands together against the register constraints. */ |
| |
| best = MAX_RECOG_OPERANDS * 2 + 600; |
| |
| swapped = 0; |
| goal_alternative_swapped = 0; |
| try_swapped: |
| |
| /* The constraints are made of several alternatives. |
| Each operand's constraint looks like foo,bar,... with commas |
| separating the alternatives. The first alternatives for all |
| operands go together, the second alternatives go together, etc. |
| |
| First loop over alternatives. */ |
| |
| for (this_alternative_number = 0; |
| this_alternative_number < n_alternatives; |
| this_alternative_number++) |
| { |
| /* Loop over operands for one constraint alternative. */ |
| /* LOSERS counts those that don't fit this alternative |
| and would require loading. */ |
| int losers = 0; |
| /* BAD is set to 1 if it some operand can't fit this alternative |
| even after reloading. */ |
| int bad = 0; |
| /* REJECT is a count of how undesirable this alternative says it is |
| if any reloading is required. If the alternative matches exactly |
| then REJECT is ignored, but otherwise it gets this much |
| counted against it in addition to the reloading needed. Each |
| ? counts three times here since we want the disparaging caused by |
| a bad register class to only count 1/3 as much. */ |
| int reject = 0; |
| |
| this_earlyclobber = 0; |
| |
| for (i = 0; i < noperands; i++) |
| { |
| char *p = constraints[i]; |
| int win = 0; |
| int did_match = 0; |
| /* 0 => this operand can be reloaded somehow for this alternative. */ |
| int badop = 1; |
| /* 0 => this operand can be reloaded if the alternative allows regs. */ |
| int winreg = 0; |
| int c; |
| rtx operand = recog_data.operand[i]; |
| int offset = 0; |
| /* Nonzero means this is a MEM that must be reloaded into a reg |
| regardless of what the constraint says. */ |
| int force_reload = 0; |
| int offmemok = 0; |
| /* Nonzero if a constant forced into memory would be OK for this |
| operand. */ |
| int constmemok = 0; |
| int earlyclobber = 0; |
| |
| /* If the predicate accepts a unary operator, it means that |
| we need to reload the operand, but do not do this for |
| match_operator and friends. */ |
| if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0) |
| operand = XEXP (operand, 0); |
| |
| /* If the operand is a SUBREG, extract |
| the REG or MEM (or maybe even a constant) within. |
| (Constants can occur as a result of reg_equiv_constant.) */ |
| |
| while (GET_CODE (operand) == SUBREG) |
| { |
| /* Offset only matters when operand is a REG and |
| it is a hard reg. This is because it is passed |
| to reg_fits_class_p if it is a REG and all pseudos |
| return 0 from that function. */ |
| if (GET_CODE (SUBREG_REG (operand)) == REG |
| && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER) |
| { |
| if (!subreg_offset_representable_p |
| (REGNO (SUBREG_REG (operand)), |
| GET_MODE (SUBREG_REG (operand)), |
| SUBREG_BYTE (operand), |
| GET_MODE (operand))) |
| force_reload = 1; |
| offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)), |
| GET_MODE (SUBREG_REG (operand)), |
| SUBREG_BYTE (operand), |
| GET_MODE (operand)); |
| } |
| |