| /* Search an insn for pseudo regs that must be in hard regs and are not. |
| Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc. |
| |
| This file is part of GNU CC. |
| |
| GNU CC 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. |
| |
| GNU CC 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 GNU CC; 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 <stdio.h> |
| #include "config.h" |
| #include "rtl.h" |
| #include "insn-config.h" |
| #include "insn-codes.h" |
| #include "recog.h" |
| #include "reload.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "flags.h" |
| #include "real.h" |
| #include "output.h" |
| #include "expr.h" |
| |
| #ifndef REGISTER_MOVE_COST |
| #define REGISTER_MOVE_COST(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 |
| |
| /* The variables set up by `find_reloads' are: |
| |
| n_reloads number of distinct reloads needed; max reload # + 1 |
| tables indexed by reload number |
| reload_in rtx for value to reload from |
| reload_out rtx for where to store reload-reg afterward if nec |
| (often the same as reload_in) |
| reload_reg_class enum reg_class, saying what regs to reload into |
| reload_inmode enum machine_mode; mode this operand should have |
| when reloaded, on input. |
| reload_outmode enum machine_mode; mode this operand should have |
| when reloaded, on output. |
| reload_optional char, nonzero for an optional reload. |
| Optional reloads are ignored unless the |
| value is already sitting in a register. |
| reload_inc int, positive amount to increment or decrement by if |
| reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC. |
| Ignored otherwise (don't assume it is zero). |
| reload_in_reg rtx. A reg for which reload_in is the equivalent. |
| If reload_in is a symbol_ref which came from |
| reg_equiv_constant, then this is the pseudo |
| which has that symbol_ref as equivalent. |
| reload_reg_rtx rtx. This is the register to reload into. |
| If it is zero when `find_reloads' returns, |
| you must find a suitable register in the class |
| specified by reload_reg_class, and store here |
| an rtx for that register with mode from |
| reload_inmode or reload_outmode. |
| reload_nocombine char, nonzero if this reload shouldn't be |
| combined with another reload. |
| reload_opnum int, operand number being reloaded. This is |
| used to group related reloads and need not always |
| be equal to the actual operand number in the insn, |
| though it current will be; for in-out operands, it |
| is one of the two operand numbers. |
| reload_when_needed enum, classifies reload as needed either for |
| addressing an input reload, addressing an output, |
| for addressing a non-reloaded mem ref, |
| or for unspecified purposes (i.e., more than one |
| of the above). |
| reload_secondary_p int, 1 if this is a secondary register for one |
| or more reloads. |
| reload_secondary_in_reload |
| reload_secondary_out_reload |
| int, gives the reload number of a secondary |
| reload, when needed; otherwise -1 |
| reload_secondary_in_icode |
| reload_secondary_out_icode |
| enum insn_code, if a secondary reload is required, |
| gives the INSN_CODE that uses the secondary |
| reload as a scratch register, or CODE_FOR_nothing |
| if the secondary reload register is to be an |
| intermediate register. */ |
| int n_reloads; |
| |
| rtx reload_in[MAX_RELOADS]; |
| rtx reload_out[MAX_RELOADS]; |
| enum reg_class reload_reg_class[MAX_RELOADS]; |
| enum machine_mode reload_inmode[MAX_RELOADS]; |
| enum machine_mode reload_outmode[MAX_RELOADS]; |
| rtx reload_reg_rtx[MAX_RELOADS]; |
| char reload_optional[MAX_RELOADS]; |
| int reload_inc[MAX_RELOADS]; |
| rtx reload_in_reg[MAX_RELOADS]; |
| char reload_nocombine[MAX_RELOADS]; |
| int reload_opnum[MAX_RELOADS]; |
| enum reload_type reload_when_needed[MAX_RELOADS]; |
| int reload_secondary_p[MAX_RELOADS]; |
| int reload_secondary_in_reload[MAX_RELOADS]; |
| int reload_secondary_out_reload[MAX_RELOADS]; |
| enum insn_code reload_secondary_in_icode[MAX_RELOADS]; |
| enum insn_code reload_secondary_out_icode[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. */ |
| }; |
| |
| /* MEM-rtx's created for pseudo-regs in stack slots not directly addressable; |
| (see reg_equiv_address). */ |
| static rtx memlocs[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)]; |
| static int n_memlocs; |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| |
| /* Save MEMs needed to copy from one class of registers to another. One MEM |
| is used per mode, but normally only one or two modes are ever used. |
| |
| We keep two versions, before and after register elimination. 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 nonegative if hard reg has been spilled. |
| This vector is passed to `find_reloads' as an argument |
| and is not changed here. */ |
| static short *static_reload_reg_p; |
| |
| /* Set to 1 in subst_reg_equivs if it changes anything. */ |
| static int subst_reg_equivs_changed; |
| |
| /* On return from push_reload, holds the reload-number for the OUT |
| operand, which can be different for that from the input operand. */ |
| static int output_reloadnum; |
| |
| /* 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))) |
| |
| static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class, |
| enum machine_mode, enum reload_type, |
| enum insn_code *)); |
| static enum reg_class find_valid_class PROTO((enum machine_mode, int)); |
| static int push_reload PROTO((rtx, rtx, rtx *, rtx *, enum reg_class, |
| enum machine_mode, enum machine_mode, |
| int, int, int, enum reload_type)); |
| static void push_replacement PROTO((rtx *, int, enum machine_mode)); |
| static void combine_reloads PROTO((void)); |
| static rtx find_dummy_reload PROTO((rtx, rtx, rtx *, rtx *, |
| enum machine_mode, enum machine_mode, |
| enum reg_class, int, int)); |
| static int earlyclobber_operand_p PROTO((rtx)); |
| static int hard_reg_set_here_p PROTO((int, int, rtx)); |
| static struct decomposition decompose PROTO((rtx)); |
| static int immune_p PROTO((rtx, rtx, struct decomposition)); |
| static int alternative_allows_memconst PROTO((char *, int)); |
| static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int)); |
| static rtx make_memloc PROTO((rtx, int)); |
| static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *, |
| int, enum reload_type, int, rtx)); |
| static rtx subst_reg_equivs PROTO((rtx)); |
| static rtx subst_indexed_address PROTO((rtx)); |
| static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *, |
| int, enum reload_type,int, rtx)); |
| static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class, |
| enum machine_mode, int, |
| enum reload_type, int)); |
| static int find_inc_amount PROTO((rtx, rtx)); |
| |
| #ifdef HAVE_SECONDARY_RELOADS |
| |
| /* Determine if any secondary reloads are needed for loading (if IN_P is |
| non-zero) or storing (if IN_P is zero) X to or from a reload register of |
| register class RELOAD_CLASS in mode RELOAD_MODE. 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 i; |
| 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_operand_predicate[(int) icode][in_p] |
| && (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode))) |
| icode = CODE_FOR_nothing; |
| |
| /* If we will be using an insn, see if it can directly handle the reload |
| register we will be using. If it can, the secondary reload is for a |
| scratch register. If it can't, we will use the secondary reload for |
| an intermediate register and require a tertiary reload for the scratch |
| register. */ |
| |
| if (icode != CODE_FOR_nothing) |
| { |
| /* If IN_P is non-zero, the reload register will be the output in |
| operand 0. If IN_P is zero, the reload register will be the input |
| in operand 1. Outputs should have an initial "=", which we must |
| skip. */ |
| |
| char insn_letter = insn_operand_constraint[(int) icode][!in_p][in_p]; |
| enum reg_class insn_class |
| = (insn_letter == 'r' ? GENERAL_REGS |
| : REG_CLASS_FROM_LETTER (insn_letter)); |
| |
| if (insn_class == NO_REGS |
| || (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=') |
| /* The scratch register's constraint must start with "=&". */ |
| || insn_operand_constraint[(int) icode][2][0] != '=' |
| || insn_operand_constraint[(int) icode][2][1] != '&') |
| abort (); |
| |
| if (reg_class_subset_p (reload_class, insn_class)) |
| mode = insn_operand_mode[(int) icode][2]; |
| else |
| { |
| char t_letter = insn_operand_constraint[(int) icode][2][2]; |
| class = insn_class; |
| t_mode = insn_operand_mode[(int) icode][2]; |
| t_class = (t_letter == 'r' ? GENERAL_REGS |
| : REG_CLASS_FROM_LETTER (t_letter)); |
| t_icode = icode; |
| icode = CODE_FOR_nothing; |
| } |
| } |
| |
| /* 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 MODE is not reload_mode and assume that the generated |
| code handles this case (it does on the Alpha, which is the only place |
| this currently happens). */ |
| |
| if (in_p && class == reload_class && mode == reload_mode) |
| 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 (reload_secondary_p[t_reload] |
| && (reg_class_subset_p (t_class, reload_reg_class[t_reload]) |
| || reg_class_subset_p (reload_reg_class[t_reload], t_class)) |
| && ((in_p && reload_inmode[t_reload] == t_mode) |
| || (! in_p && reload_outmode[t_reload] == t_mode)) |
| && ((in_p && (reload_secondary_in_icode[t_reload] |
| == CODE_FOR_nothing)) |
| || (! in_p &&(reload_secondary_out_icode[t_reload] |
| == CODE_FOR_nothing))) |
| && (reg_class_size[(int) t_class] == 1 |
| #ifdef SMALL_REGISTER_CLASSES |
| || SMALL_REGISTER_CLASSES |
| #endif |
| ) |
| && MERGABLE_RELOADS (secondary_type, |
| reload_when_needed[t_reload], |
| opnum, reload_opnum[t_reload])) |
| { |
| if (in_p) |
| reload_inmode[t_reload] = t_mode; |
| if (! in_p) |
| reload_outmode[t_reload] = t_mode; |
| |
| if (reg_class_subset_p (t_class, reload_reg_class[t_reload])) |
| reload_reg_class[t_reload] = t_class; |
| |
| reload_opnum[t_reload] = MIN (reload_opnum[t_reload], opnum); |
| reload_optional[t_reload] &= optional; |
| reload_secondary_p[t_reload] = 1; |
| if (MERGE_TO_OTHER (secondary_type, reload_when_needed[t_reload], |
| opnum, reload_opnum[t_reload])) |
| reload_when_needed[t_reload] = RELOAD_OTHER; |
| } |
| |
| if (t_reload == n_reloads) |
| { |
| /* We need to make a new tertiary reload for this register class. */ |
| reload_in[t_reload] = reload_out[t_reload] = 0; |
| reload_reg_class[t_reload] = t_class; |
| reload_inmode[t_reload] = in_p ? t_mode : VOIDmode; |
| reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode; |
| reload_reg_rtx[t_reload] = 0; |
| reload_optional[t_reload] = optional; |
| reload_inc[t_reload] = 0; |
| /* Maybe we could combine these, but it seems too tricky. */ |
| reload_nocombine[t_reload] = 1; |
| reload_in_reg[t_reload] = 0; |
| reload_opnum[t_reload] = opnum; |
| reload_when_needed[t_reload] = secondary_type; |
| reload_secondary_in_reload[t_reload] = -1; |
| reload_secondary_out_reload[t_reload] = -1; |
| reload_secondary_in_icode[t_reload] = CODE_FOR_nothing; |
| reload_secondary_out_icode[t_reload] = CODE_FOR_nothing; |
| reload_secondary_p[t_reload] = 1; |
| |
| n_reloads++; |
| } |
| } |
| |
| /* See if we can reuse an existing secondary reload. */ |
| for (s_reload = 0; s_reload < n_reloads; s_reload++) |
| if (reload_secondary_p[s_reload] |
| && (reg_class_subset_p (class, reload_reg_class[s_reload]) |
| || reg_class_subset_p (reload_reg_class[s_reload], class)) |
| && ((in_p && reload_inmode[s_reload] == mode) |
| || (! in_p && reload_outmode[s_reload] == mode)) |
| && ((in_p && reload_secondary_in_reload[s_reload] == t_reload) |
| || (! in_p && reload_secondary_out_reload[s_reload] == t_reload)) |
| && ((in_p && reload_secondary_in_icode[s_reload] == t_icode) |
| || (! in_p && reload_secondary_out_icode[s_reload] == t_icode)) |
| && (reg_class_size[(int) class] == 1 |
| #ifdef SMALL_REGISTER_CLASSES |
| || SMALL_REGISTER_CLASSES |
| #endif |
| ) |
| && MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload], |
| opnum, reload_opnum[s_reload])) |
| { |
| if (in_p) |
| reload_inmode[s_reload] = mode; |
| if (! in_p) |
| reload_outmode[s_reload] = mode; |
| |
| if (reg_class_subset_p (class, reload_reg_class[s_reload])) |
| reload_reg_class[s_reload] = class; |
| |
| reload_opnum[s_reload] = MIN (reload_opnum[s_reload], opnum); |
| reload_optional[s_reload] &= optional; |
| reload_secondary_p[s_reload] = 1; |
| if (MERGE_TO_OTHER (secondary_type, reload_when_needed[s_reload], |
| opnum, reload_opnum[s_reload])) |
| reload_when_needed[s_reload] = RELOAD_OTHER; |
| } |
| |
| if (s_reload == n_reloads) |
| { |
| /* We need to make a new secondary reload for this register class. */ |
| reload_in[s_reload] = reload_out[s_reload] = 0; |
| reload_reg_class[s_reload] = class; |
| |
| reload_inmode[s_reload] = in_p ? mode : VOIDmode; |
| reload_outmode[s_reload] = ! in_p ? mode : VOIDmode; |
| reload_reg_rtx[s_reload] = 0; |
| reload_optional[s_reload] = optional; |
| reload_inc[s_reload] = 0; |
| /* Maybe we could combine these, but it seems too tricky. */ |
| reload_nocombine[s_reload] = 1; |
| reload_in_reg[s_reload] = 0; |
| reload_opnum[s_reload] = opnum; |
| reload_when_needed[s_reload] = secondary_type; |
| reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1; |
| reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1; |
| reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing; |
| reload_secondary_out_icode[s_reload] |
| = ! in_p ? t_icode : CODE_FOR_nothing; |
| reload_secondary_p[s_reload] = 1; |
| |
| n_reloads++; |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* If we need a memory location to copy between the two reload regs, |
| set it up now. */ |
| |
| if (in_p && icode == CODE_FOR_nothing |
| && SECONDARY_MEMORY_NEEDED (class, reload_class, mode)) |
| get_secondary_mem (x, mode, opnum, type); |
| |
| 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; |
| 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) |
| 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, 0); |
| 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, NULL_PTR, 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 () |
| { |
| bzero ((char *) secondary_memlocs, 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). Abort if no such class exists. */ |
| |
| static enum reg_class |
| find_valid_class (m1, n) |
| enum machine_mode m1; |
| int n; |
| { |
| int class; |
| int regno; |
| enum reg_class best_class; |
| int best_size = 0; |
| |
| 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 && reg_class_size[class] > best_size) |
| best_class = class, best_size = reg_class_size[class]; |
| } |
| |
| if (best_size == 0) |
| abort (); |
| |
| return best_class; |
| } |
| |
| /* 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 non-zero, 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. */ |
| |
| static int |
| push_reload (in, out, inloc, outloc, class, |
| inmode, outmode, strict_low, optional, opnum, type) |
| register 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; |
| { |
| register 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) |
| { |
| register 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) |
| { |
| register 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)) |
| { |
| if (GET_CODE (XEXP (in, 0)) == POST_INC |
| || GET_CODE (XEXP (in, 0)) == POST_DEC) |
| in = gen_rtx (MEM, GET_MODE (in), XEXP (XEXP (in, 0), 0)); |
| if (GET_CODE (XEXP (in, 0)) == PRE_INC |
| || GET_CODE (XEXP (in, 0)) == PRE_DEC) |
| out = gen_rtx (MEM, GET_MODE (out), XEXP (XEXP (out, 0), 0)); |
| } |
| |
| /* 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_WORD is nonzero, we |
| cannot reload just the inside since we might end up with the wrong |
| register class. */ |
| |
| if (in != 0 && GET_CODE (in) == SUBREG && SUBREG_WORD (in) == 0 |
| #ifdef CLASS_CANNOT_CHANGE_SIZE |
| && class != CLASS_CANNOT_CHANGE_SIZE |
| #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 |
| )) |
| || (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_WORD (in) == 0) |
| && ((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) |
| != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), |
| GET_MODE (SUBREG_REG (in))))) |
| || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (in)) |
| + SUBREG_WORD (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 CLASS_CANNOT_CHANGE_SIZE |
| || (GET_CODE (SUBREG_REG (in)) == REG |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER |
| && (TEST_HARD_REG_BIT |
| (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE], |
| REGNO (SUBREG_REG (in)))) |
| && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) |
| != GET_MODE_SIZE (inmode))) |
| #endif |
| )) |
| { |
| in_subreg_loc = inloc; |
| inloc = &SUBREG_REG (in); |
| in = *inloc; |
| #ifndef LOAD_EXTEND_OP |
| 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_WORD != 0. */ |
| |
| if (in != 0 && GET_CODE (in) == SUBREG |
| && (CONSTANT_P (SUBREG_REG (in)) |
| || (GET_CODE (SUBREG_REG (in)) == REG |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER |
| && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)) |
| + SUBREG_WORD (in), |
| inmode) |
| || (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) |
| != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), |
| GET_MODE (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), NULL_PTR, |
| find_valid_class (inmode, SUBREG_WORD (in)), |
| 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_WORD (out) == 0 |
| #ifdef CLASS_CANNOT_CHANGE_SIZE |
| && class != CLASS_CANNOT_CHANGE_SIZE |
| #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)))))) |
| || (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) |
| != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), |
| GET_MODE (SUBREG_REG (out))))) |
| || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (out)) |
| + SUBREG_WORD (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 CLASS_CANNOT_CHANGE_SIZE |
| || (GET_CODE (SUBREG_REG (out)) == REG |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER |
| && (TEST_HARD_REG_BIT |
| (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE], |
| REGNO (SUBREG_REG (out)))) |
| && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) |
| != GET_MODE_SIZE (outmode))) |
| #endif |
| )) |
| { |
| out_subreg_loc = outloc; |
| outloc = &SUBREG_REG (out); |
| out = *outloc; |
| #ifndef LOAD_EXTEND_OP |
| 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 && GET_CODE (out) == SUBREG |
| && GET_CODE (SUBREG_REG (out)) == REG |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER |
| && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)) + SUBREG_WORD (out), |
| outmode) |
| || (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) |
| != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), |
| GET_MODE (SUBREG_REG (out))))))) |
| { |
| /* 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_WORD (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), |
| REGNO (SUBREG_REG (in)) + SUBREG_WORD (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), |
| REGNO (SUBREG_REG (out)) + SUBREG_WORD (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; |
| } |
| } |
| |
| if (class == NO_REGS) |
| abort (); |
| |
| /* 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, reload_reg_class[i]) |
| || reg_class_subset_p (reload_reg_class[i], class)) |
| /* If the existing reload has a register, it must fit our class. */ |
| && (reload_reg_rtx[i] == 0 |
| || TEST_HARD_REG_BIT (reg_class_contents[(int) class], |
| true_regnum (reload_reg_rtx[i]))) |
| && ((in != 0 && MATCHES (reload_in[i], in) && ! dont_share |
| && (out == 0 || reload_out[i] == 0 || MATCHES (reload_out[i], out))) |
| || |
| (out != 0 && MATCHES (reload_out[i], out) |
| && (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in)))) |
| && (reg_class_size[(int) class] == 1 |
| #ifdef SMALL_REGISTER_CLASSES |
| || SMALL_REGISTER_CLASSES |
| #endif |
| ) |
| && MERGABLE_RELOADS (type, reload_when_needed[i], |
| opnum, reload_opnum[i])) |
| break; |
| |
| /* 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. */ |
| if (i == n_reloads) |
| for (i = 0; i < n_reloads; i++) |
| if ((reg_class_subset_p (class, reload_reg_class[i]) |
| || reg_class_subset_p (reload_reg_class[i], class)) |
| /* If the existing reload has a register, it must fit our class. */ |
| && (reload_reg_rtx[i] == 0 |
| || TEST_HARD_REG_BIT (reg_class_contents[(int) class], |
| true_regnum (reload_reg_rtx[i]))) |
| && out == 0 && reload_out[i] == 0 && reload_in[i] != 0 |
| && ((GET_CODE (in) == REG |
| && (GET_CODE (reload_in[i]) == POST_INC |
| || GET_CODE (reload_in[i]) == POST_DEC |
| || GET_CODE (reload_in[i]) == PRE_INC |
| || GET_CODE (reload_in[i]) == PRE_DEC) |
| && MATCHES (XEXP (reload_in[i], 0), in)) |
| || |
| (GET_CODE (reload_in[i]) == REG |
| && (GET_CODE (in) == POST_INC |
| || GET_CODE (in) == POST_DEC |
| || GET_CODE (in) == PRE_INC |
| || GET_CODE (in) == PRE_DEC) |
| && MATCHES (XEXP (in, 0), reload_in[i]))) |
| && (reg_class_size[(int) class] == 1 |
| #ifdef SMALL_REGISTER_CLASSES |
| || SMALL_REGISTER_CLASSES |
| #endif |
| ) |
| && MERGABLE_RELOADS (type, reload_when_needed[i], |
| opnum, reload_opnum[i])) |
| { |
| /* Make sure reload_in ultimately has the increment, |
| not the plain register. */ |
| if (GET_CODE (in) == REG) |
| in = reload_in[i]; |
| break; |
| } |
| |
| 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. */ |
| |
| i = n_reloads; |
| reload_in[i] = in; |
| reload_out[i] = out; |
| reload_reg_class[i] = class; |
| reload_inmode[i] = inmode; |
| reload_outmode[i] = outmode; |
| reload_reg_rtx[i] = 0; |
| reload_optional[i] = optional; |
| reload_inc[i] = 0; |
| reload_nocombine[i] = 0; |
| reload_in_reg[i] = inloc ? *inloc : 0; |
| reload_opnum[i] = opnum; |
| reload_when_needed[i] = type; |
| reload_secondary_in_reload[i] = secondary_in_reload; |
| reload_secondary_out_reload[i] = secondary_out_reload; |
| reload_secondary_in_icode[i] = secondary_in_icode; |
| reload_secondary_out_icode[i] = secondary_out_icode; |
| reload_secondary_p[i] = 0; |
| |
| n_reloads++; |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* If a memory location is needed for the copy, make one. */ |
| if (in != 0 && GET_CODE (in) == REG |
| && REGNO (in) < FIRST_PSEUDO_REGISTER |
| && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)), |
| class, inmode)) |
| get_secondary_mem (in, inmode, opnum, type); |
| |
| if (out != 0 && GET_CODE (out) == REG |
| && REGNO (out) < FIRST_PSEUDO_REGISTER |
| && SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (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 (reload_inmode[i])) |
| reload_inmode[i] = inmode; |
| if (outmode != VOIDmode |
| && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i])) |
| reload_outmode[i] = outmode; |
| if (in != 0) |
| reload_in[i] = in; |
| if (out != 0) |
| reload_out[i] = out; |
| if (reg_class_subset_p (class, reload_reg_class[i])) |
| reload_reg_class[i] = class; |
| reload_optional[i] &= optional; |
| if (MERGE_TO_OTHER (type, reload_when_needed[i], |
| opnum, reload_opnum[i])) |
| reload_when_needed[i] = RELOAD_OTHER; |
| reload_opnum[i] = MIN (reload_opnum[i], opnum); |
| } |
| |
| /* If the ostensible rtx being reload 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) |
| reload_nocombine[i] = 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; |
| reload_out[i] = 0; |
| reload_inc[i] = 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 (reload_inc[i] == 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) |
| { |
| register 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) |
| { |
| register 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 reload_reg_rtx[i] |
| to that one. */ |
| |
| if (in != 0 && out != 0 && in != out && reload_reg_rtx[i] == 0) |
| { |
| reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc, |
| inmode, outmode, |
| reload_reg_class[i], 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 (reload_reg_rtx[i] == out |
| && (GET_CODE (in) == REG || CONSTANT_P (in)) |
| && 0 != find_equiv_reg (in, this_insn, 0, REGNO (out), |
| static_reload_reg_p, i, inmode)) |
| reload_in[i] = 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 (reload_reg_rtx[i] == 0 && in != 0) |
| { |
| rtx note; |
| int regno; |
| |
| 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, |
| inmode)), |
| 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, |
| inmode)), |
| 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 (inmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) |
| && HARD_REGNO_MODE_OK (regno, inmode) |
| && GET_MODE_SIZE (outmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) |
| && HARD_REGNO_MODE_OK (regno, outmode) |
| && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno) |
| && !fixed_regs[regno]) |
| { |
| reload_reg_rtx[i] = gen_rtx (REG, inmode, 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) |
| { |
| register struct replacement *r = &replacements[n_replacements++]; |
| r->what = reloadnum; |
| r->where = loc; |
| r->subreg_loc = 0; |
| r->mode = 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; |
| } |
| |
| /* 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 (reload_out[i] != 0) |
| { |
| if (output_reload >= 0) |
| return; |
| output_reload = i; |
| } |
| |
| if (output_reload < 0 || reload_optional[output_reload]) |
| return; |
| |
| /* An input-output reload isn't combinable. */ |
| |
| if (reload_in[output_reload] != 0) |
| return; |
| |
| /* If this reload is for an earlyclobber operand, we can't do anything. */ |
| if (earlyclobber_operand_p (reload_out[output_reload])) |
| return; |
| |
| /* Check each input reload; can we combine it? */ |
| |
| for (i = 0; i < n_reloads; i++) |
| if (reload_in[i] && ! reload_optional[i] && ! reload_nocombine[i] |
| /* Life span of this reload must not extend past main insn. */ |
| && reload_when_needed[i] != RELOAD_FOR_OUTPUT_ADDRESS |
| && reload_when_needed[i] != RELOAD_FOR_OUTADDR_ADDRESS |
| && reload_when_needed[i] != RELOAD_OTHER |
| && (CLASS_MAX_NREGS (reload_reg_class[i], reload_inmode[i]) |
| == CLASS_MAX_NREGS (reload_reg_class[output_reload], |
| reload_outmode[output_reload])) |
| && reload_inc[i] == 0 |
| && reload_reg_rtx[i] == 0 |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* Don't combine two reloads with different secondary |
| memory locations. */ |
| && (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]] == 0 |
| || secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] == 0 |
| || rtx_equal_p (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]], |
| secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]])) |
| #endif |
| && ( |
| #ifdef SMALL_REGISTER_CLASSES |
| SMALL_REGISTER_CLASSES |
| #else |
| 0 |
| #endif |
| ? reload_reg_class[i] == reload_reg_class[output_reload] |
| : (reg_class_subset_p (reload_reg_class[i], |
| reload_reg_class[output_reload]) |
| || reg_class_subset_p (reload_reg_class[output_reload], |
| reload_reg_class[i]))) |
| && (MATCHES (reload_in[i], reload_out[output_reload]) |
| /* 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 (reload_out[output_reload], |
| reload_in[i]) |
| /* 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 (reload_in[i]) == REG |
| && reg_overlap_mentioned_for_reload_p (reload_in[i], |
| reload_out[output_reload])))) |
| && (reg_class_size[(int) reload_reg_class[i]] |
| #ifdef SMALL_REGISTER_CLASSES |
| || SMALL_REGISTER_CLASSES |
| #endif |
| ) |
| /* We will allow making things slightly worse by combining an |
| input and an output, but no worse than that. */ |
| && (reload_when_needed[i] == RELOAD_FOR_INPUT |
| || reload_when_needed[i] == RELOAD_FOR_OUTPUT)) |
| { |
| int j; |
| |
| /* We have found a reload to combine with! */ |
| reload_out[i] = reload_out[output_reload]; |
| reload_outmode[i] = reload_outmode[output_reload]; |
| /* Mark the old output reload as inoperative. */ |
| reload_out[output_reload] = 0; |
| /* The combined reload is needed for the entire insn. */ |
| reload_when_needed[i] = RELOAD_OTHER; |
| /* If the output reload had a secondary reload, copy it. */ |
| if (reload_secondary_out_reload[output_reload] != -1) |
| { |
| reload_secondary_out_reload[i] |
| = reload_secondary_out_reload[output_reload]; |
| reload_secondary_out_icode[i] |
| = reload_secondary_out_icode[output_reload]; |
| } |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* Copy any secondary MEM. */ |
| if (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] != 0) |
| secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]] |
| = secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]]; |
| #endif |
| /* If required, minimize the register class. */ |
| if (reg_class_subset_p (reload_reg_class[output_reload], |
| reload_reg_class[i])) |
| reload_reg_class[i] = reload_reg_class[output_reload]; |
| |
| /* 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_n_operands[INSN_CODE (this_insn)]; i++) |
| if (insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '=' |
| || insn_operand_constraint[INSN_CODE (this_insn)][i][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), |
| reload_out[output_reload]) |
| && REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER |
| && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), reload_outmode[output_reload]) |
| && TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[output_reload]], |
| REGNO (XEXP (note, 0))) |
| && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), reload_outmode[output_reload]) |
| <= 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 = reload_secondary_out_reload[output_reload]) == -1 |
| || (! (TEST_HARD_REG_BIT |
| (reg_class_contents[(int) reload_reg_class[secondary_out]], |
| REGNO (XEXP (note, 0)))) |
| && ((secondary_out = reload_secondary_out_reload[secondary_out]) == -1 |
| || ! (TEST_HARD_REG_BIT |
| (reg_class_contents[(int) reload_reg_class[secondary_out]], |
| REGNO (XEXP (note, 0))))))) |
| && ! fixed_regs[REGNO (XEXP (note, 0))]) |
| { |
| reload_reg_rtx[output_reload] = gen_rtx (REG, |
| reload_outmode[output_reload], |
| 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 reload_out[FOR_REAL]. |
| |
| 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 non-zero 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; |
| |
| /* Find the inside of any subregs. */ |
| while (GET_CODE (out) == SUBREG) |
| { |
| out_offset = SUBREG_WORD (out); |
| out = SUBREG_REG (out); |
| } |
| while (GET_CODE (in) == SUBREG) |
| { |
| in_offset = SUBREG_WORD (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) |
| { |
| register int regno = REGNO (out) + out_offset; |
| 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 |
| /* A fixed reg that can overlap other regs better not be used |
| for reloading in any way. */ |
| #ifdef OVERLAPPING_REGNO_P |
| && ! (fixed_regs[regno] && OVERLAPPING_REGNO_P (regno)) |
| #endif |
| && ! refers_to_regno_for_reload_p (regno, regno + nwords, |
| PATTERN (this_insn), outloc)) |
| { |
| 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))) |
| { |
| register int regno = REGNO (in) + in_offset; |
| int nwords = HARD_REGNO_NREGS (regno, inmode); |
| |
| if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, NULL_PTR) |
| && ! 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))) |
| { |
| 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) |
| reload_out[for_real] = 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. */ |
| |
| static 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) |
| register int beg_regno, end_regno; |
| rtx x; |
| { |
| if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) |
| { |
| register rtx op0 = SET_DEST (x); |
| while (GET_CODE (op0) == SUBREG) |
| op0 = SUBREG_REG (op0); |
| if (GET_CODE (op0) == REG) |
| { |
| register 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) |
| { |
| register 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; |
| register 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) |
| register rtx x, y; |
| { |
| register int i; |
| register RTX_CODE code = GET_CODE (x); |
| register 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))) |
| { |
| register int j; |
| |
| if (code == SUBREG) |
| { |
| i = REGNO (SUBREG_REG (x)); |
| if (i >= FIRST_PSEUDO_REGISTER) |
| goto slow; |
| i += SUBREG_WORD (x); |
| } |
| else |
| i = REGNO (x); |
| |
| if (GET_CODE (y) == SUBREG) |
| { |
| j = REGNO (SUBREG_REG (y)); |
| if (j >= FIRST_PSEUDO_REGISTER) |
| goto slow; |
| j += SUBREG_WORD (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, an postincrement matches ordinary indexing |
| if the postincrement is the output operand. */ |
| if (code == POST_DEC || code == POST_INC) |
| return operands_match_p (XEXP (x, 0), y); |
| /* Two preincrements are invalid |
| because the assembler insn would increment only once. |
| On the other hand, an 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) |
| 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; |
| 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; |
| |
| /* 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; |
| } |
| |
| /* Return the number of times character C occurs in string S. */ |
| |
| int |
| n_occurrences (c, s) |
| int c; |
| char *s; |
| { |
| int n = 0; |
| while (*s) |
| n += (*s++ == c); |
| return n; |
| } |
| |
| /* 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; |
| if (GET_CODE (x) == MEM) |
| { |
| rtx base, 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) == 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, NULL_PTR); |
| 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. */ |
| |
| void |
| find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) |
| rtx insn; |
| int replace, ind_levels; |
| int live_known; |
| short *reload_reg_p; |
| { |
| #ifdef REGISTER_CONSTRAINTS |
| |
| register int insn_code_number; |
| register int i, j; |
| int noperands; |
| /* These are the constraints for the insn. We don't change them. */ |
| char *constraints1[MAX_RECOG_OPERANDS]; |
| /* 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]; |
| /* 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_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; |
| int operand_reloadnum[MAX_RECOG_OPERANDS]; |
| int goal_alternative_matches[MAX_RECOG_OPERANDS]; |
| int goal_alternative_matched[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, this_earlyclobber; |
| enum machine_mode operand_mode[MAX_RECOG_OPERANDS]; |
| |
| this_insn = insn; |
| this_insn_is_asm = 0; /* Tentative. */ |
| n_reloads = 0; |
| n_replacements = 0; |
| n_memlocs = 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. */ |
| |
| bzero ((char *) secondary_memlocs_elim, sizeof secondary_memlocs_elim); |
| #endif |
| |
| /* Find what kind of insn this is. NOPERANDS gets number of operands. |
| Make OPERANDS point to a vector of operand values. |
| Make OPERAND_LOCS point to a vector of pointers to |
| where the operands were found. |
| Fill CONSTRAINTS and CONSTRAINTS1 with pointers to the |
| constraint-strings for this insn. |
| Return if the insn needs no reload processing. */ |
| |
| switch (GET_CODE (body)) |
| { |
| case USE: |
| case CLOBBER: |
| case ASM_INPUT: |
| case ADDR_VEC: |
| case ADDR_DIFF_VEC: |
| return; |
| |
| case SET: |
| /* 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 (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 (REGNO_REG_CLASS (REGNO (SET_SRC (body))), |
| REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2) |
| return; |
| case PARALLEL: |
| case ASM_OPERANDS: |
| reload_n_operands = noperands = asm_noperands (body); |
| if (noperands >= 0) |
| { |
| /* This insn is an `asm' with operands. */ |
| |
| insn_code_number = -1; |
| this_insn_is_asm = 1; |
| |
| /* expand_asm_operands makes sure there aren't too many operands. */ |
| if (noperands > MAX_RECOG_OPERANDS) |
| abort (); |
| |
| /* Now get the operand values and constraints out of the insn. */ |
| |
| decode_asm_operands (body, recog_operand, recog_operand_loc, |
| constraints, operand_mode); |
| if (noperands > 0) |
| { |
| bcopy ((char *) constraints, (char *) constraints1, |
| noperands * sizeof (char *)); |
| n_alternatives = n_occurrences (',', constraints[0]) + 1; |
| for (i = 1; i < noperands; i++) |
| if (n_alternatives != n_occurrences (',', constraints[i]) + 1) |
| { |
| error_for_asm (insn, "operand constraints differ in number of alternatives"); |
| /* Avoid further trouble with this insn. */ |
| PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx); |
| n_reloads = 0; |
| return; |
| } |
| } |
| break; |
| } |
| |
| default: |
| /* Ordinary insn: recognize it, get the operands via insn_extract |
| and get the constraints. */ |
| |
| insn_code_number = recog_memoized (insn); |
| if (insn_code_number < 0) |
| fatal_insn_not_found (insn); |
| |
| reload_n_operands = noperands = insn_n_operands[insn_code_number]; |
| n_alternatives = insn_n_alternatives[insn_code_number]; |
| /* Just return "no reloads" if insn has no operands with constraints. */ |
| if (n_alternatives == 0) |
| return; |
| insn_extract (insn); |
| for (i = 0; i < noperands; i++) |
| { |
| constraints[i] = constraints1[i] |
| = insn_operand_constraint[insn_code_number][i]; |
| operand_mode[i] = insn_operand_mode[insn_code_number][i]; |
| } |
| } |
| |
| if (noperands == 0) |
| return; |
| |
| 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++) |
| { |
| register char *p; |
| register int c; |
| |
| substed_operand[i] = recog_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) |
| { |
| if (this_insn_is_asm) |
| warning_for_asm (this_insn, |
| "`%%' constraint used with last operand"); |
| else |
| abort (); |
| } |
| else |
| commutative = i; |
| } |
| else if (c >= '0' && c <= '9') |
| { |
| c -= '0'; |
| operands_match[c][i] |
| = operands_match_p (recog_operand[c], recog_operand[i]); |
| |
| /* An operand may not match itself. */ |
| if (c == i) |
| { |
| if (this_insn_is_asm) |
| warning_for_asm (this_insn, |
| "operand %d has constraint %d", i, c); |
| else |
| 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_operand[other], recog_operand[i]); |
| } |
| if (i == commutative || i == commutative + 1) |
| { |
| int other = i + (i == commutative ? 1 : -1); |
| operands_match[c][other] |
| = operands_match_p (recog_operand[c], recog_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++) |
| { |
| register RTX_CODE code = GET_CODE (recog_operand[i]); |
| |
| address_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') |
| { |
| find_reloads_address (VOIDmode, NULL_PTR, |
| recog_operand[i], recog_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_operand_loc[i])) == 'o' |
| || GET_CODE (*recog_operand_loc[i]) == SUBREG) |
| && (GET_CODE (recog_operand[i]) == MULT |
| || GET_CODE (recog_operand[i]) == PLUS)) |
| { |
| INSN_CODE (insn) = -1; |
| find_reloads (insn, replace, ind_levels, live_known, |
| reload_reg_p); |
| return; |
| } |
| |
| substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]; |
| } |
| else if (code == MEM) |
| { |
| if (find_reloads_address (GET_MODE (recog_operand[i]), |
| recog_operand_loc[i], |
| XEXP (recog_operand[i], 0), |
| &XEXP (recog_operand[i], 0), |
| i, address_type[i], ind_levels, insn)) |
| address_reloaded[i] = 1; |
| substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]; |
| } |
| else if (code == SUBREG) |
| substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] |
| = find_reloads_toplev (recog_operand[i], i, address_type[i], |
| ind_levels, |
| set != 0 |
| && &SET_DEST (set) == recog_operand_loc[i]); |
| 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_operand[i] = *recog_operand_loc[i] |
| = find_reloads_toplev (recog_operand[i], i, address_type[i], |
| ind_levels, 0); |
| 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. */ |
| register int regno = REGNO (recog_operand[i]); |
| if (reg_equiv_constant[regno] != 0 |
| && (set == 0 || &SET_DEST (set) != recog_operand_loc[i])) |
| substed_operand[i] = recog_operand[i] |
| = reg_equiv_constant[regno]; |
| #if 0 /* This might screw code in reload1.c to delete prior output-reload |
| that feeds this insn. */ |
| if (reg_equiv_mem[regno] != 0) |
| substed_operand[i] = recog_operand[i] |
| = reg_equiv_mem[regno]; |
| #endif |
| if (reg_equiv_address[regno] != 0) |
| { |
| /* If reg_equiv_address is not a constant address, copy it, |
| since it may be shared. */ |
| /* We must rerun eliminate_regs, in case the elimination |
| offsets have changed. */ |
| rtx address = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], |
| 0, NULL_RTX, 0), |
| 0); |
| |
| if (rtx_varies_p (address)) |
| address = copy_rtx (address); |
| |
| /* If this is an output operand, we must output a CLOBBER |
| after INSN so find_equiv_reg knows REGNO is being written. |
| Mark this insn specially, do we can put our output reloads |
| after it. */ |
| |
| if (modified[i] != RELOAD_READ) |
| PUT_MODE (emit_insn_after (gen_rtx (CLOBBER, VOIDmode, |
| recog_operand[i]), |
| insn), |
| DImode); |
| |
| *recog_operand_loc[i] = recog_operand[i] |
| = gen_rtx (MEM, GET_MODE (recog_operand[i]), address); |
| RTX_UNCHANGING_P (recog_operand[i]) |
| = RTX_UNCHANGING_P (regno_reg_rtx[regno]); |
| find_reloads_address (GET_MODE (recog_operand[i]), |
| recog_operand_loc[i], |
| XEXP (recog_operand[i], 0), |
| &XEXP (recog_operand[i], 0), |
| i, address_type[i], ind_levels, insn); |
| substed_operand[i] = recog_operand[i] = *recog_operand_loc[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_operand[i]); |
| preferred_class[i] |
| = ((code == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER) |
| ? reg_preferred_class (REGNO (recog_operand[i])) : NO_REGS); |
| pref_or_nothing[i] |
| = (code == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER |
| && reg_alternate_class (REGNO (recog_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_operand[0] == SET_DEST (set) |
| && recog_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 + 300; |
| |
| 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++) |
| { |
| register char *p = constraints[i]; |
| register int win = 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; |
| register rtx operand = recog_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. */ |
| if (GET_RTX_CLASS (GET_CODE (operand)) == '1') |
| 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 += SUBREG_WORD (operand); |
| operand = SUBREG_REG (operand); |
| /* Force reload if this is a constant or PLUS or if there may may |
| be a problem accessing OPERAND in the outer mode. */ |
| if (CONSTANT_P (operand) |
| || GET_CODE (operand) == PLUS |
| /* We must force a reload of paradoxical SUBREGs |
| of a MEM because the alignment of the inner value |
| may not be enough to do the outer reference. On |
| big-endian machines, it may also reference outside |
| the object. |
| |
| On machines that extend byte operations and we have a |
| SUBREG where both the inner and outer modes are no wider |
| than a word and the inner mode is narrower, is integral, |
| and gets extended when loaded from memory, combine.c has |
| made assumptions about the behavior of the machine in such |
| register access. If the data is, in fact, in memory we |
| must always load using the size assumed to be in the |
| register and let the insn do the different-sized |
| accesses. */ |
| || ((GET_CODE (operand) == MEM |
| || (GET_CODE (operand)== REG |
| && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) |
| && (((GET_MODE_BITSIZE (GET_MODE (operand)) |
| < BIGGEST_ALIGNMENT) |
| && (GET_MODE_SIZE (operand_mode[i]) |
| > GET_MODE_SIZE (GET_MODE (operand)))) |
| || (GET_CODE (operand) == MEM && BYTES_BIG_ENDIAN) |
| #ifdef LOAD_EXTEND_OP |
| || (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD |
| && (GET_MODE_SIZE (GET_MODE (operand)) |
| <= UNITS_PER_WORD) |
| && (GET_MODE_SIZE (operand_mode[i]) |
| > GET_MODE_SIZE (GET_MODE (operand))) |
| && INTEGRAL_MODE_P (GET_MODE (operand)) |
| && LOAD_EXTEND_OP (GET_MODE (operand)) != NIL) |
| #endif |
| )) |
| /* Subreg of a hard reg which can't handle the subreg's mode |
| or which would handle that mode in the wrong number of |
| registers for subregging to work. */ |
| || (GET_CODE (operand) == REG |
| && REGNO (operand) < FIRST_PSEUDO_REGISTER |
| && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD |
| && (GET_MODE_SIZE (GET_MODE (operand)) |
| > UNITS_PER_WORD) |
| && ((GET_MODE_SIZE (GET_MODE (operand)) |
| / UNITS_PER_WORD) |
| != HARD_REGNO_NREGS (REGNO (operand), |
| GET_MODE (operand)))) |
| || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset, |
| operand_mode[i])))) |
| force_reload = 1; |
| } |
| |
| this_alternative[i] = (int) NO_REGS; |
| this_alternative_win[i] = 0; |
| this_alternative_offmemok[i] = 0; |
| this_alternative_earlyclobber[i] = 0; |
| this_alternative_matches[i] = -1; |
| |
| /* An empty constraint or empty alternative |
| allows anything which matched the pattern. */ |
| if (*p == 0 || *p == ',') |
| win = 1, badop = 0; |
| |
| /* Scan this alternative's specs for this operand; |
| set WIN if the operand fits any letter in this alternative. |
| Otherwise, clear BADOP if this operand could |
| fit some letter after reloads, |
| or set WINREG if this operand could fit after reloads |
| provided the constraint allows some registers. */ |
| |
| while (*p && (c = *p++) != ',') |
| switch (c) |
| { |
| case '=': |
| case '+': |
| case '*': |
| break; |
| |
| case '%': |
| /* The last operand should not be marked commutative. */ |
| if (i != noperands - 1) |
| commutative = i; |
| break; |
| |
| case '?': |
| reject += 3; |
| break; |
| |
| case '!': |
| reject = 300; |
| break; |
| |
| case '#': |
| /* Ignore rest of this alternative as far as |
| reloading is concerned. */ |
| while (*p && *p != ',') p++; |
| break; |
| |
| case '0': |
| case '1': |
| case '2': |
| case '3': |
| case '4': |
| c -= '0'; |
| this_alternative_matches[i] = c; |
| /* We are supposed to match a previous operand. |
| If we do, we win if that one did. |
| If we do not, count both of the operands as losers. |
| (This is too conservative, since most of the time |
| only a single reload insn will be needed to make |
| the two operands win. As a result, this alternative |
| may be rejected when it is actually desirable.) */ |
| if ((swapped && (c != commutative || i != commutative + 1)) |
| /* If we are matching as if two operands were swapped, |
| also pretend that operands_match had been computed |
| with swapped. |
| But if I is the second of those and C is the first, |
| don't exchange them, because operands_match is valid |
| only on one side of its diagonal. */ |
| ? (operands_match |
| [(c == commutative || c == commutative + 1) |
| ? 2*commutative + 1 - c : c] |
| [(i == commutative || i == commutative + 1) |
| ? 2*commutative + 1 - i : i]) |
| : operands_match[c][i]) |
| win = this_alternative_win[c]; |
| else |
| { |
| /* Operands don't match. */ |
| rtx value; |
| /* Retroactively mark the operand we had to match |
| as a loser, if it wasn't already. */ |
| if (this_alternative_win[c]) |
| losers++; |
| this_alternative_win[c] = 0; |
| if (this_alternative[c] == (int) NO_REGS) |
| bad = 1; |
| /* But count the pair only once in the total badness of |
| this alternative, if the pair can be a dummy reload. */ |
| value |
| = find_dummy_reload (recog_operand[i], recog_operand[c], |
| recog_operand_loc[i], recog_operand_loc[c], |
| operand_mode[i], operand_mode[c], |
| this_alternative[c], -1, |
| this_alternative_earlyclobber[c]); |
| |
| if (value != 0) |
| losers--; |
| } |
| /* This can be fixed with reloads if the operand |
| we are supposed to match can be fixed with reloads. */ |
| badop = 0; |
| this_alternative[i] = this_alternative[c]; |
| |
| /* If we have to reload this operand and some previous |
| operand also had to match the same thing as this |
| operand, we don't know how to do that. So reject this |
| alternative. */ |
| if (! win || force_reload) |
| for (j = 0; j < i; j++) |
| if (this_alternative_matches[j] |
| == this_alternative_matches[i]) |
| badop = 1; |
| |
| break; |
| |
| case 'p': |
| /* All necessary reloads for an address_operand |
| were handled in find_reloads_address. */ |
| this_alternative[i] = (int) BASE_REG_CLASS; |
| win = 1; |
| break; |
| |
| case 'm': |
| if (force_reload) |
| break; |
| if (GET_CODE (operand) == MEM |
| || (GET_CODE (operand) == REG |
| && REGNO (operand) >= FIRST_PSEUDO_REGISTER |
| && reg_renumber[REGNO (operand)] < 0)) |
| win = 1; |
| if (CONSTANT_P (operand)) |
| badop = 0; |
| constmemok = 1; |
| break; |
| |
| case '<': |
| if (GET_CODE (operand) == MEM |
| && ! address_reloaded[i] |
| && (GET_CODE (XEXP (operand, 0)) == PRE_DEC |
| || GET_CODE (XEXP (operand, 0)) == POST_DEC)) |
| win = 1; |
| break; |
| |
| case '>': |
| if (GET_CODE (operand) == MEM |
| && ! address_reloaded[i] |
| && (GET_CODE (XEXP (operand, 0)) == PRE_INC |
| || GET_CODE (XEXP (operand, 0)) == POST_INC)) |
| win = 1; |
| break; |
| |
| /* Memory operand whose address is not offsettable. */ |
| case 'V': |
| if (force_reload) |
| break; |
| if (GET_CODE (operand) == MEM |
| && ! (ind_levels ? offsettable_memref_p (operand) |
| : offsettable_nonstrict_memref_p (operand)) |
| /* Certain mem addresses will become offsettable |
| after they themselves are reloaded. This is important; |
| we don't want our own handling of unoffsettables |
| to override the handling of reg_equiv_address. */ |
| && !(GET_CODE (XEXP (operand, 0)) == REG |
| && (ind_levels == 0 |
| || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0))) |
| win = 1; |
| break; |
| |
| /* Memory operand whose address is offsettable. */ |
| case 'o': |
| if (force_reload) |
| break; |
| if ((GET_CODE (operand) == MEM |
| /* If IND_LEVELS, find_reloads_address won't reload a |
| pseudo that didn't get a hard reg, so we have to |
| reject that case. */ |
| && (ind_levels ? offsettable_memref_p (operand) |
| : offsettable_nonstrict_memref_p (operand))) |
| /* A reloaded auto-increment address is offsettable, |
| because it is now just a simple register indirect. */ |
| || (GET_CODE (operand) == MEM |
| && address_reloaded[i] |
| && (GET_CODE (XEXP (operand, 0)) == PRE_INC |
| || GET_CODE (XEXP (operand, 0)) == PRE_DEC |
| || GET_CODE (XEXP (operand, 0)) == POST_INC |
| || GET_CODE (XEXP (operand, 0)) == POST_DEC)) |
| /* Certain mem addresses will become offsettable |
| after they themselves are reloaded. This is important; |
| we don't want our own handling of unoffsettables |
| to override the handling of reg_equiv_address. */ |
| || (GET_CODE (operand) == MEM |
| && GET_CODE (XEXP (operand, 0)) == REG |
| && (ind_levels |