| /* Search an insn for pseudo regs that must be in hard regs and are not. |
| Copyright (C) 1987-2015 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* This file contains subroutines used only from the file reload1.c. |
| It knows how to scan one insn for operands and values |
| that need to be copied into registers to make valid code. |
| It also finds other operands and values which are valid |
| but for which equivalent values in registers exist and |
| ought to be used instead. |
| |
| Before processing the first insn of the function, call `init_reload'. |
| init_reload actually has to be called earlier anyway. |
| |
| To scan an insn, call `find_reloads'. This does two things: |
| 1. sets up tables describing which values must be reloaded |
| for this insn, and what kind of hard regs they must be reloaded into; |
| 2. optionally record the locations where those values appear in |
| the data, so they can be replaced properly later. |
| This is done only if the second arg to `find_reloads' is nonzero. |
| |
| The third arg to `find_reloads' specifies the number of levels |
| of indirect addressing supported by the machine. If it is zero, |
| indirect addressing is not valid. If it is one, (MEM (REG n)) |
| is valid even if (REG n) did not get a hard register; if it is two, |
| (MEM (MEM (REG n))) is also valid even if (REG n) did not get a |
| hard register, and similarly for higher values. |
| |
| Then you must choose the hard regs to reload those pseudo regs into, |
| and generate appropriate load insns before this insn and perhaps |
| also store insns after this insn. Set up the array `reload_reg_rtx' |
| to contain the REG rtx's for the registers you used. In some |
| cases `find_reloads' will return a nonzero value in `reload_reg_rtx' |
| for certain reloads. Then that tells you which register to use, |
| so you do not need to allocate one. But you still do need to add extra |
| instructions to copy the value into and out of that register. |
| |
| Finally you must call `subst_reloads' to substitute the reload reg rtx's |
| into the locations already recorded. |
| |
| NOTE SIDE EFFECTS: |
| |
| find_reloads can alter the operands of the instruction it is called on. |
| |
| 1. Two operands of any sort may be interchanged, if they are in a |
| commutative instruction. |
| This happens only if find_reloads thinks the instruction will compile |
| better that way. |
| |
| 2. Pseudo-registers that are equivalent to constants are replaced |
| with those constants if they are not in hard registers. |
| |
| 1 happens every time find_reloads is called. |
| 2 happens only when REPLACE is 1, which is only when |
| actually doing the reloads, not when just counting them. |
| |
| Using a reload register for several reloads in one insn: |
| |
| When an insn has reloads, it is considered as having three parts: |
| the input reloads, the insn itself after reloading, and the output reloads. |
| Reloads of values used in memory addresses are often needed for only one part. |
| |
| When this is so, reload_when_needed records which part needs the reload. |
| Two reloads for different parts of the insn can share the same reload |
| register. |
| |
| When a reload is used for addresses in multiple parts, or when it is |
| an ordinary operand, it is classified as RELOAD_OTHER, and cannot share |
| a register with any other reload. */ |
| |
| #define REG_OK_STRICT |
| |
| /* We do not enable this with ENABLE_CHECKING, since it is awfully slow. */ |
| #undef DEBUG_RELOAD |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "rtl-error.h" |
| #include "tm_p.h" |
| #include "insn-config.h" |
| #include "symtab.h" |
| #include "hashtab.h" |
| #include "hash-set.h" |
| #include "vec.h" |
| #include "machmode.h" |
| #include "hard-reg-set.h" |
| #include "input.h" |
| #include "function.h" |
| #include "rtl.h" |
| #include "flags.h" |
| #include "statistics.h" |
| #include "double-int.h" |
| #include "real.h" |
| #include "fixed-value.h" |
| #include "alias.h" |
| #include "wide-int.h" |
| #include "inchash.h" |
| #include "tree.h" |
| #include "expmed.h" |
| #include "dojump.h" |
| #include "explow.h" |
| #include "calls.h" |
| #include "emit-rtl.h" |
| #include "varasm.h" |
| #include "stmt.h" |
| #include "expr.h" |
| #include "insn-codes.h" |
| #include "optabs.h" |
| #include "recog.h" |
| #include "dominance.h" |
| #include "cfg.h" |
| #include "predict.h" |
| #include "basic-block.h" |
| #include "df.h" |
| #include "reload.h" |
| #include "regs.h" |
| #include "addresses.h" |
| #include "params.h" |
| #include "target.h" |
| #include "ira.h" |
| |
| /* True if X is a constant that can be forced into the constant pool. |
| MODE is the mode of the operand, or VOIDmode if not known. */ |
| #define CONST_POOL_OK_P(MODE, X) \ |
| ((MODE) != VOIDmode \ |
| && CONSTANT_P (X) \ |
| && GET_CODE (X) != HIGH \ |
| && !targetm.cannot_force_const_mem (MODE, X)) |
| |
| /* True if C is a non-empty register class that has too few registers |
| to be safely used as a reload target class. */ |
| |
| static inline bool |
| small_register_class_p (reg_class_t rclass) |
| { |
| return (reg_class_size [(int) rclass] == 1 |
| || (reg_class_size [(int) rclass] >= 1 |
| && targetm.class_likely_spilled_p (rclass))); |
| } |
| |
| |
| /* All reloads of the current insn are recorded here. See reload.h for |
| comments. */ |
| int n_reloads; |
| struct reload rld[MAX_RELOADS]; |
| |
| /* All the "earlyclobber" operands of the current insn |
| are recorded here. */ |
| int n_earlyclobbers; |
| rtx reload_earlyclobbers[MAX_RECOG_OPERANDS]; |
| |
| int reload_n_operands; |
| |
| /* Replacing reloads. |
| |
| If `replace_reloads' is nonzero, then as each reload is recorded |
| an entry is made for it in the table `replacements'. |
| Then later `subst_reloads' can look through that table and |
| perform all the replacements needed. */ |
| |
| /* Nonzero means record the places to replace. */ |
| static int replace_reloads; |
| |
| /* Each replacement is recorded with a structure like this. */ |
| struct replacement |
| { |
| rtx *where; /* Location to store in */ |
| int what; /* which reload this is for */ |
| machine_mode mode; /* mode it must have */ |
| }; |
| |
| static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)]; |
| |
| /* Number of replacements currently recorded. */ |
| static int n_replacements; |
| |
| /* Used to track what is modified by an operand. */ |
| struct decomposition |
| { |
| int reg_flag; /* Nonzero if referencing a register. */ |
| int safe; /* Nonzero if this can't conflict with anything. */ |
| rtx base; /* Base address for MEM. */ |
| HOST_WIDE_INT start; /* Starting offset or register number. */ |
| HOST_WIDE_INT end; /* Ending offset or register number. */ |
| }; |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| |
| /* Save MEMs needed to copy from one class of registers to another. One MEM |
| is used per mode, but normally only one or two modes are ever used. |
| |
| We keep two versions, before and after register elimination. The one |
| after register elimination is record separately for each operand. This |
| is done in case the address is not valid to be sure that we separately |
| reload each. */ |
| |
| static rtx secondary_memlocs[NUM_MACHINE_MODES]; |
| static rtx secondary_memlocs_elim[NUM_MACHINE_MODES][MAX_RECOG_OPERANDS]; |
| static int secondary_memlocs_elim_used = 0; |
| #endif |
| |
| /* The instruction we are doing reloads for; |
| so we can test whether a register dies in it. */ |
| static rtx_insn *this_insn; |
| |
| /* Nonzero if this instruction is a user-specified asm with operands. */ |
| static int this_insn_is_asm; |
| |
| /* If hard_regs_live_known is nonzero, |
| we can tell which hard regs are currently live, |
| at least enough to succeed in choosing dummy reloads. */ |
| static int hard_regs_live_known; |
| |
| /* Indexed by hard reg number, |
| element is nonnegative if hard reg has been spilled. |
| This vector is passed to `find_reloads' as an argument |
| and is not changed here. */ |
| static short *static_reload_reg_p; |
| |
| /* Set to 1 in subst_reg_equivs if it changes anything. */ |
| static int subst_reg_equivs_changed; |
| |
| /* On return from push_reload, holds the reload-number for the OUT |
| operand, which can be different for that from the input operand. */ |
| static int output_reloadnum; |
| |
| /* Compare two RTX's. */ |
| #define MATCHES(x, y) \ |
| (x == y || (x != 0 && (REG_P (x) \ |
| ? REG_P (y) && REGNO (x) == REGNO (y) \ |
| : rtx_equal_p (x, y) && ! side_effects_p (x)))) |
| |
| /* Indicates if two reloads purposes are for similar enough things that we |
| can merge their reloads. */ |
| #define MERGABLE_RELOADS(when1, when2, op1, op2) \ |
| ((when1) == RELOAD_OTHER || (when2) == RELOAD_OTHER \ |
| || ((when1) == (when2) && (op1) == (op2)) \ |
| || ((when1) == RELOAD_FOR_INPUT && (when2) == RELOAD_FOR_INPUT) \ |
| || ((when1) == RELOAD_FOR_OPERAND_ADDRESS \ |
| && (when2) == RELOAD_FOR_OPERAND_ADDRESS) \ |
| || ((when1) == RELOAD_FOR_OTHER_ADDRESS \ |
| && (when2) == RELOAD_FOR_OTHER_ADDRESS)) |
| |
| /* Nonzero if these two reload purposes produce RELOAD_OTHER when merged. */ |
| #define MERGE_TO_OTHER(when1, when2, op1, op2) \ |
| ((when1) != (when2) \ |
| || ! ((op1) == (op2) \ |
| || (when1) == RELOAD_FOR_INPUT \ |
| || (when1) == RELOAD_FOR_OPERAND_ADDRESS \ |
| || (when1) == RELOAD_FOR_OTHER_ADDRESS)) |
| |
| /* If we are going to reload an address, compute the reload type to |
| use. */ |
| #define ADDR_TYPE(type) \ |
| ((type) == RELOAD_FOR_INPUT_ADDRESS \ |
| ? RELOAD_FOR_INPADDR_ADDRESS \ |
| : ((type) == RELOAD_FOR_OUTPUT_ADDRESS \ |
| ? RELOAD_FOR_OUTADDR_ADDRESS \ |
| : (type))) |
| |
| static int push_secondary_reload (int, rtx, int, int, enum reg_class, |
| machine_mode, enum reload_type, |
| enum insn_code *, secondary_reload_info *); |
| static enum reg_class find_valid_class (machine_mode, machine_mode, |
| int, unsigned int); |
| static void push_replacement (rtx *, int, machine_mode); |
| static void dup_replacements (rtx *, rtx *); |
| static void combine_reloads (void); |
| static int find_reusable_reload (rtx *, rtx, enum reg_class, |
| enum reload_type, int, int); |
| static rtx find_dummy_reload (rtx, rtx, rtx *, rtx *, machine_mode, |
| machine_mode, reg_class_t, int, int); |
| static int hard_reg_set_here_p (unsigned int, unsigned int, rtx); |
| static struct decomposition decompose (rtx); |
| static int immune_p (rtx, rtx, struct decomposition); |
| static bool alternative_allows_const_pool_ref (rtx, const char *, int); |
| static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, |
| rtx_insn *, int *); |
| static rtx make_memloc (rtx, int); |
| static int maybe_memory_address_addr_space_p (machine_mode, rtx, |
| addr_space_t, rtx *); |
| static int find_reloads_address (machine_mode, rtx *, rtx, rtx *, |
| int, enum reload_type, int, rtx_insn *); |
| static rtx subst_reg_equivs (rtx, rtx_insn *); |
| static rtx subst_indexed_address (rtx); |
| static void update_auto_inc_notes (rtx_insn *, int, int); |
| static int find_reloads_address_1 (machine_mode, addr_space_t, rtx, int, |
| enum rtx_code, enum rtx_code, rtx *, |
| int, enum reload_type,int, rtx_insn *); |
| static void find_reloads_address_part (rtx, rtx *, enum reg_class, |
| machine_mode, int, |
| enum reload_type, int); |
| static rtx find_reloads_subreg_address (rtx, int, enum reload_type, |
| int, rtx_insn *, int *); |
| static void copy_replacements_1 (rtx *, rtx *, int); |
| static int find_inc_amount (rtx, rtx); |
| static int refers_to_mem_for_reload_p (rtx); |
| static int refers_to_regno_for_reload_p (unsigned int, unsigned int, |
| rtx, rtx *); |
| |
| /* Add NEW to reg_equiv_alt_mem_list[REGNO] if it's not present in the |
| list yet. */ |
| |
| static void |
| push_reg_equiv_alt_mem (int regno, rtx mem) |
| { |
| rtx it; |
| |
| for (it = reg_equiv_alt_mem_list (regno); it; it = XEXP (it, 1)) |
| if (rtx_equal_p (XEXP (it, 0), mem)) |
| return; |
| |
| reg_equiv_alt_mem_list (regno) |
| = alloc_EXPR_LIST (REG_EQUIV, mem, |
| reg_equiv_alt_mem_list (regno)); |
| } |
| |
| /* Determine if any secondary reloads are needed for loading (if IN_P is |
| nonzero) or storing (if IN_P is zero) X to or from a reload register of |
| register class RELOAD_CLASS in mode RELOAD_MODE. If secondary reloads |
| are needed, push them. |
| |
| Return the reload number of the secondary reload we made, or -1 if |
| we didn't need one. *PICODE is set to the insn_code to use if we do |
| need a secondary reload. */ |
| |
| static int |
| push_secondary_reload (int in_p, rtx x, int opnum, int optional, |
| enum reg_class reload_class, |
| machine_mode reload_mode, enum reload_type type, |
| enum insn_code *picode, secondary_reload_info *prev_sri) |
| { |
| enum reg_class rclass = NO_REGS; |
| enum reg_class scratch_class; |
| machine_mode mode = reload_mode; |
| enum insn_code icode = CODE_FOR_nothing; |
| enum insn_code t_icode = CODE_FOR_nothing; |
| enum reload_type secondary_type; |
| int s_reload, t_reload = -1; |
| const char *scratch_constraint; |
| secondary_reload_info sri; |
| |
| if (type == RELOAD_FOR_INPUT_ADDRESS |
| || type == RELOAD_FOR_OUTPUT_ADDRESS |
| || type == RELOAD_FOR_INPADDR_ADDRESS |
| || type == RELOAD_FOR_OUTADDR_ADDRESS) |
| secondary_type = type; |
| else |
| secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS; |
| |
| *picode = CODE_FOR_nothing; |
| |
| /* If X is a paradoxical SUBREG, use the inner value to determine both the |
| mode and object being reloaded. */ |
| if (paradoxical_subreg_p (x)) |
| { |
| x = SUBREG_REG (x); |
| reload_mode = GET_MODE (x); |
| } |
| |
| /* If X is a pseudo-register that has an equivalent MEM (actually, if it |
| is still a pseudo-register by now, it *must* have an equivalent MEM |
| but we don't want to assume that), use that equivalent when seeing if |
| a secondary reload is needed since whether or not a reload is needed |
| might be sensitive to the form of the MEM. */ |
| |
| if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER |
| && reg_equiv_mem (REGNO (x))) |
| x = reg_equiv_mem (REGNO (x)); |
| |
| sri.icode = CODE_FOR_nothing; |
| sri.prev_sri = prev_sri; |
| rclass = (enum reg_class) targetm.secondary_reload (in_p, x, reload_class, |
| reload_mode, &sri); |
| icode = (enum insn_code) sri.icode; |
| |
| /* If we don't need any secondary registers, done. */ |
| if (rclass == NO_REGS && icode == CODE_FOR_nothing) |
| return -1; |
| |
| if (rclass != NO_REGS) |
| t_reload = push_secondary_reload (in_p, x, opnum, optional, rclass, |
| reload_mode, type, &t_icode, &sri); |
| |
| /* If we will be using an insn, the secondary reload is for a |
| scratch register. */ |
| |
| if (icode != CODE_FOR_nothing) |
| { |
| /* If IN_P is nonzero, the reload register will be the output in |
| operand 0. If IN_P is zero, the reload register will be the input |
| in operand 1. Outputs should have an initial "=", which we must |
| skip. */ |
| |
| /* ??? It would be useful to be able to handle only two, or more than |
| three, operands, but for now we can only handle the case of having |
| exactly three: output, input and one temp/scratch. */ |
| gcc_assert (insn_data[(int) icode].n_operands == 3); |
| |
| /* ??? We currently have no way to represent a reload that needs |
| an icode to reload from an intermediate tertiary reload register. |
| We should probably have a new field in struct reload to tag a |
| chain of scratch operand reloads onto. */ |
| gcc_assert (rclass == NO_REGS); |
| |
| scratch_constraint = insn_data[(int) icode].operand[2].constraint; |
| gcc_assert (*scratch_constraint == '='); |
| scratch_constraint++; |
| if (*scratch_constraint == '&') |
| scratch_constraint++; |
| scratch_class = (reg_class_for_constraint |
| (lookup_constraint (scratch_constraint))); |
| |
| rclass = scratch_class; |
| mode = insn_data[(int) icode].operand[2].mode; |
| } |
| |
| /* This case isn't valid, so fail. Reload is allowed to use the same |
| register for RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT reloads, but |
| in the case of a secondary register, we actually need two different |
| registers for correct code. We fail here to prevent the possibility of |
| silently generating incorrect code later. |
| |
| The convention is that secondary input reloads are valid only if the |
| secondary_class is different from class. If you have such a case, you |
| can not use secondary reloads, you must work around the problem some |
| other way. |
| |
| Allow this when a reload_in/out pattern is being used. I.e. assume |
| that the generated code handles this case. */ |
| |
| gcc_assert (!in_p || rclass != reload_class || icode != CODE_FOR_nothing |
| || t_icode != CODE_FOR_nothing); |
| |
| /* See if we can reuse an existing secondary reload. */ |
| for (s_reload = 0; s_reload < n_reloads; s_reload++) |
| if (rld[s_reload].secondary_p |
| && (reg_class_subset_p (rclass, rld[s_reload].rclass) |
| || reg_class_subset_p (rld[s_reload].rclass, rclass)) |
| && ((in_p && rld[s_reload].inmode == mode) |
| || (! in_p && rld[s_reload].outmode == mode)) |
| && ((in_p && rld[s_reload].secondary_in_reload == t_reload) |
| || (! in_p && rld[s_reload].secondary_out_reload == t_reload)) |
| && ((in_p && rld[s_reload].secondary_in_icode == t_icode) |
| || (! in_p && rld[s_reload].secondary_out_icode == t_icode)) |
| && (small_register_class_p (rclass) |
| || targetm.small_register_classes_for_mode_p (VOIDmode)) |
| && MERGABLE_RELOADS (secondary_type, rld[s_reload].when_needed, |
| opnum, rld[s_reload].opnum)) |
| { |
| if (in_p) |
| rld[s_reload].inmode = mode; |
| if (! in_p) |
| rld[s_reload].outmode = mode; |
| |
| if (reg_class_subset_p (rclass, rld[s_reload].rclass)) |
| rld[s_reload].rclass = rclass; |
| |
| rld[s_reload].opnum = MIN (rld[s_reload].opnum, opnum); |
| rld[s_reload].optional &= optional; |
| rld[s_reload].secondary_p = 1; |
| if (MERGE_TO_OTHER (secondary_type, rld[s_reload].when_needed, |
| opnum, rld[s_reload].opnum)) |
| rld[s_reload].when_needed = RELOAD_OTHER; |
| |
| break; |
| } |
| |
| if (s_reload == n_reloads) |
| { |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* If we need a memory location to copy between the two reload regs, |
| set it up now. Note that we do the input case before making |
| the reload and the output case after. This is due to the |
| way reloads are output. */ |
| |
| if (in_p && icode == CODE_FOR_nothing |
| && SECONDARY_MEMORY_NEEDED (rclass, reload_class, mode)) |
| { |
| get_secondary_mem (x, reload_mode, opnum, type); |
| |
| /* We may have just added new reloads. Make sure we add |
| the new reload at the end. */ |
| s_reload = n_reloads; |
| } |
| #endif |
| |
| /* We need to make a new secondary reload for this register class. */ |
| rld[s_reload].in = rld[s_reload].out = 0; |
| rld[s_reload].rclass = rclass; |
| |
| rld[s_reload].inmode = in_p ? mode : VOIDmode; |
| rld[s_reload].outmode = ! in_p ? mode : VOIDmode; |
| rld[s_reload].reg_rtx = 0; |
| rld[s_reload].optional = optional; |
| rld[s_reload].inc = 0; |
| /* Maybe we could combine these, but it seems too tricky. */ |
| rld[s_reload].nocombine = 1; |
| rld[s_reload].in_reg = 0; |
| rld[s_reload].out_reg = 0; |
| rld[s_reload].opnum = opnum; |
| rld[s_reload].when_needed = secondary_type; |
| rld[s_reload].secondary_in_reload = in_p ? t_reload : -1; |
| rld[s_reload].secondary_out_reload = ! in_p ? t_reload : -1; |
| rld[s_reload].secondary_in_icode = in_p ? t_icode : CODE_FOR_nothing; |
| rld[s_reload].secondary_out_icode |
| = ! in_p ? t_icode : CODE_FOR_nothing; |
| rld[s_reload].secondary_p = 1; |
| |
| n_reloads++; |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| if (! in_p && icode == CODE_FOR_nothing |
| && SECONDARY_MEMORY_NEEDED (reload_class, rclass, mode)) |
| get_secondary_mem (x, mode, opnum, type); |
| #endif |
| } |
| |
| *picode = icode; |
| return s_reload; |
| } |
| |
| /* If a secondary reload is needed, return its class. If both an intermediate |
| register and a scratch register is needed, we return the class of the |
| intermediate register. */ |
| reg_class_t |
| secondary_reload_class (bool in_p, reg_class_t rclass, machine_mode mode, |
| rtx x) |
| { |
| enum insn_code icode; |
| secondary_reload_info sri; |
| |
| sri.icode = CODE_FOR_nothing; |
| sri.prev_sri = NULL; |
| rclass |
| = (enum reg_class) targetm.secondary_reload (in_p, x, rclass, mode, &sri); |
| icode = (enum insn_code) sri.icode; |
| |
| /* If there are no secondary reloads at all, we return NO_REGS. |
| If an intermediate register is needed, we return its class. */ |
| if (icode == CODE_FOR_nothing || rclass != NO_REGS) |
| return rclass; |
| |
| /* No intermediate register is needed, but we have a special reload |
| pattern, which we assume for now needs a scratch register. */ |
| return scratch_reload_class (icode); |
| } |
| |
| /* ICODE is the insn_code of a reload pattern. Check that it has exactly |
| three operands, verify that operand 2 is an output operand, and return |
| its register class. |
| ??? We'd like to be able to handle any pattern with at least 2 operands, |
| for zero or more scratch registers, but that needs more infrastructure. */ |
| enum reg_class |
| scratch_reload_class (enum insn_code icode) |
| { |
| const char *scratch_constraint; |
| enum reg_class rclass; |
| |
| gcc_assert (insn_data[(int) icode].n_operands == 3); |
| scratch_constraint = insn_data[(int) icode].operand[2].constraint; |
| gcc_assert (*scratch_constraint == '='); |
| scratch_constraint++; |
| if (*scratch_constraint == '&') |
| scratch_constraint++; |
| rclass = reg_class_for_constraint (lookup_constraint (scratch_constraint)); |
| gcc_assert (rclass != NO_REGS); |
| return rclass; |
| } |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| |
| /* Return a memory location that will be used to copy X in mode MODE. |
| If we haven't already made a location for this mode in this insn, |
| call find_reloads_address on the location being returned. */ |
| |
| rtx |
| get_secondary_mem (rtx x ATTRIBUTE_UNUSED, machine_mode mode, |
| int opnum, enum reload_type type) |
| { |
| rtx loc; |
| int mem_valid; |
| |
| /* By default, if MODE is narrower than a word, widen it to a word. |
| This is required because most machines that require these memory |
| locations do not support short load and stores from all registers |
| (e.g., FP registers). */ |
| |
| #ifdef SECONDARY_MEMORY_NEEDED_MODE |
| mode = SECONDARY_MEMORY_NEEDED_MODE (mode); |
| #else |
| if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD && INTEGRAL_MODE_P (mode)) |
| mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0); |
| #endif |
| |
| /* If we already have made a MEM for this operand in MODE, return it. */ |
| if (secondary_memlocs_elim[(int) mode][opnum] != 0) |
| return secondary_memlocs_elim[(int) mode][opnum]; |
| |
| /* If this is the first time we've tried to get a MEM for this mode, |
| allocate a new one. `something_changed' in reload will get set |
| by noticing that the frame size has changed. */ |
| |
| if (secondary_memlocs[(int) mode] == 0) |
| { |
| #ifdef SECONDARY_MEMORY_NEEDED_RTX |
| secondary_memlocs[(int) mode] = SECONDARY_MEMORY_NEEDED_RTX (mode); |
| #else |
| secondary_memlocs[(int) mode] |
| = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); |
| #endif |
| } |
| |
| /* Get a version of the address doing any eliminations needed. If that |
| didn't give us a new MEM, make a new one if it isn't valid. */ |
| |
| loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX); |
| mem_valid = strict_memory_address_addr_space_p (mode, XEXP (loc, 0), |
| MEM_ADDR_SPACE (loc)); |
| |
| if (! mem_valid && loc == secondary_memlocs[(int) mode]) |
| loc = copy_rtx (loc); |
| |
| /* The only time the call below will do anything is if the stack |
| offset is too large. In that case IND_LEVELS doesn't matter, so we |
| can just pass a zero. Adjust the type to be the address of the |
| corresponding object. If the address was valid, save the eliminated |
| address. If it wasn't valid, we need to make a reload each time, so |
| don't save it. */ |
| |
| if (! mem_valid) |
| { |
| type = (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS |
| : type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS |
| : RELOAD_OTHER); |
| |
| find_reloads_address (mode, &loc, XEXP (loc, 0), &XEXP (loc, 0), |
| opnum, type, 0, 0); |
| } |
| |
| secondary_memlocs_elim[(int) mode][opnum] = loc; |
| if (secondary_memlocs_elim_used <= (int)mode) |
| secondary_memlocs_elim_used = (int)mode + 1; |
| return loc; |
| } |
| |
| /* Clear any secondary memory locations we've made. */ |
| |
| void |
| clear_secondary_mem (void) |
| { |
| memset (secondary_memlocs, 0, sizeof secondary_memlocs); |
| } |
| #endif /* SECONDARY_MEMORY_NEEDED */ |
| |
| |
| /* Find the largest class which has at least one register valid in |
| mode INNER, and which for every such register, that register number |
| plus N is also valid in OUTER (if in range) and is cheap to move |
| into REGNO. Such a class must exist. */ |
| |
| static enum reg_class |
| find_valid_class (machine_mode outer ATTRIBUTE_UNUSED, |
| machine_mode inner ATTRIBUTE_UNUSED, int n, |
| unsigned int dest_regno ATTRIBUTE_UNUSED) |
| { |
| int best_cost = -1; |
| int rclass; |
| int regno; |
| enum reg_class best_class = NO_REGS; |
| enum reg_class dest_class ATTRIBUTE_UNUSED = REGNO_REG_CLASS (dest_regno); |
| unsigned int best_size = 0; |
| int cost; |
| |
| for (rclass = 1; rclass < N_REG_CLASSES; rclass++) |
| { |
| int bad = 0; |
| int good = 0; |
| for (regno = 0; regno < FIRST_PSEUDO_REGISTER - n && ! bad; regno++) |
| if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno)) |
| { |
| if (HARD_REGNO_MODE_OK (regno, inner)) |
| { |
| good = 1; |
| if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n) |
| && ! HARD_REGNO_MODE_OK (regno + n, outer)) |
| bad = 1; |
| } |
| } |
| |
| if (bad || !good) |
| continue; |
| cost = register_move_cost (outer, (enum reg_class) rclass, dest_class); |
| |
| if ((reg_class_size[rclass] > best_size |
| && (best_cost < 0 || best_cost >= cost)) |
| || best_cost > cost) |
| { |
| best_class = (enum reg_class) rclass; |
| best_size = reg_class_size[rclass]; |
| best_cost = register_move_cost (outer, (enum reg_class) rclass, |
| dest_class); |
| } |
| } |
| |
| gcc_assert (best_size != 0); |
| |
| return best_class; |
| } |
| |
| /* We are trying to reload a subreg of something that is not a register. |
| Find the largest class which contains only registers valid in |
| mode MODE. OUTER is the mode of the subreg, DEST_CLASS the class in |
| which we would eventually like to obtain the object. */ |
| |
| static enum reg_class |
| find_valid_class_1 (machine_mode outer ATTRIBUTE_UNUSED, |
| machine_mode mode ATTRIBUTE_UNUSED, |
| enum reg_class dest_class ATTRIBUTE_UNUSED) |
| { |
| int best_cost = -1; |
| int rclass; |
| int regno; |
| enum reg_class best_class = NO_REGS; |
| unsigned int best_size = 0; |
| int cost; |
| |
| for (rclass = 1; rclass < N_REG_CLASSES; rclass++) |
| { |
| int bad = 0; |
| for (regno = 0; regno < FIRST_PSEUDO_REGISTER && !bad; regno++) |
| { |
| if (in_hard_reg_set_p (reg_class_contents[rclass], mode, regno) |
| && !HARD_REGNO_MODE_OK (regno, mode)) |
| bad = 1; |
| } |
| |
| if (bad) |
| continue; |
| |
| cost = register_move_cost (outer, (enum reg_class) rclass, dest_class); |
| |
| if ((reg_class_size[rclass] > best_size |
| && (best_cost < 0 || best_cost >= cost)) |
| || best_cost > cost) |
| { |
| best_class = (enum reg_class) rclass; |
| best_size = reg_class_size[rclass]; |
| best_cost = register_move_cost (outer, (enum reg_class) rclass, |
| dest_class); |
| } |
| } |
| |
| gcc_assert (best_size != 0); |
| |
| #ifdef LIMIT_RELOAD_CLASS |
| best_class = LIMIT_RELOAD_CLASS (mode, best_class); |
| #endif |
| return best_class; |
| } |
| |
| /* Return the number of a previously made reload that can be combined with |
| a new one, or n_reloads if none of the existing reloads can be used. |
| OUT, RCLASS, TYPE and OPNUM are the same arguments as passed to |
| push_reload, they determine the kind of the new reload that we try to |
| combine. P_IN points to the corresponding value of IN, which can be |
| modified by this function. |
| DONT_SHARE is nonzero if we can't share any input-only reload for IN. */ |
| |
| static int |
| find_reusable_reload (rtx *p_in, rtx out, enum reg_class rclass, |
| enum reload_type type, int opnum, int dont_share) |
| { |
| rtx in = *p_in; |
| int i; |
| /* We can't merge two reloads if the output of either one is |
| earlyclobbered. */ |
| |
| if (earlyclobber_operand_p (out)) |
| return n_reloads; |
| |
| /* We can use an existing reload if the class is right |
| and at least one of IN and OUT is a match |
| and the other is at worst neutral. |
| (A zero compared against anything is neutral.) |
| |
| For targets with 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 (rclass, rld[i].rclass) |
| || reg_class_subset_p (rld[i].rclass, rclass)) |
| /* If the existing reload has a register, it must fit our class. */ |
| && (rld[i].reg_rtx == 0 |
| || TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], |
| true_regnum (rld[i].reg_rtx))) |
| && ((in != 0 && MATCHES (rld[i].in, in) && ! dont_share |
| && (out == 0 || rld[i].out == 0 || MATCHES (rld[i].out, out))) |
| || (out != 0 && MATCHES (rld[i].out, out) |
| && (in == 0 || rld[i].in == 0 || MATCHES (rld[i].in, in)))) |
| && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out)) |
| && (small_register_class_p (rclass) |
| || targetm.small_register_classes_for_mode_p (VOIDmode)) |
| && MERGABLE_RELOADS (type, rld[i].when_needed, opnum, rld[i].opnum)) |
| return i; |
| |
| /* Reloading a plain reg for input can match a reload to postincrement |
| that reg, since the postincrement's value is the right value. |
| Likewise, it can match a preincrement reload, since we regard |
| the preincrementation as happening before any ref in this insn |
| to that register. */ |
| for (i = 0; i < n_reloads; i++) |
| if ((reg_class_subset_p (rclass, rld[i].rclass) |
| || reg_class_subset_p (rld[i].rclass, rclass)) |
| /* If the existing reload has a register, it must fit our |
| class. */ |
| && (rld[i].reg_rtx == 0 |
| || TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], |
| true_regnum (rld[i].reg_rtx))) |
| && out == 0 && rld[i].out == 0 && rld[i].in != 0 |
| && ((REG_P (in) |
| && GET_RTX_CLASS (GET_CODE (rld[i].in)) == RTX_AUTOINC |
| && MATCHES (XEXP (rld[i].in, 0), in)) |
| || (REG_P (rld[i].in) |
| && GET_RTX_CLASS (GET_CODE (in)) == RTX_AUTOINC |
| && MATCHES (XEXP (in, 0), rld[i].in))) |
| && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out)) |
| && (small_register_class_p (rclass) |
| || targetm.small_register_classes_for_mode_p (VOIDmode)) |
| && MERGABLE_RELOADS (type, rld[i].when_needed, |
| opnum, rld[i].opnum)) |
| { |
| /* Make sure reload_in ultimately has the increment, |
| not the plain register. */ |
| if (REG_P (in)) |
| *p_in = rld[i].in; |
| return i; |
| } |
| return n_reloads; |
| } |
| |
| /* Return true if X is a SUBREG that will need reloading of its SUBREG_REG |
| expression. MODE is the mode that X will be used in. OUTPUT is true if |
| the function is invoked for the output part of an enclosing reload. */ |
| |
| static bool |
| reload_inner_reg_of_subreg (rtx x, machine_mode mode, bool output) |
| { |
| rtx inner; |
| |
| /* Only SUBREGs are problematical. */ |
| if (GET_CODE (x) != SUBREG) |
| return false; |
| |
| inner = SUBREG_REG (x); |
| |
| /* If INNER is a constant or PLUS, then INNER will need reloading. */ |
| if (CONSTANT_P (inner) || GET_CODE (inner) == PLUS) |
| return true; |
| |
| /* If INNER is not a hard register, then INNER will not need reloading. */ |
| if (!(REG_P (inner) && HARD_REGISTER_P (inner))) |
| return false; |
| |
| /* If INNER is not ok for MODE, then INNER will need reloading. */ |
| if (!HARD_REGNO_MODE_OK (subreg_regno (x), mode)) |
| return true; |
| |
| /* If this is for an output, and the outer part is a word or smaller, |
| INNER is larger than a word and the number of registers in INNER is |
| not the same as the number of words in INNER, then INNER will need |
| reloading (with an in-out reload). */ |
| return (output |
| && GET_MODE_SIZE (mode) <= UNITS_PER_WORD |
| && GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD |
| && ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD) |
| != (int) hard_regno_nregs[REGNO (inner)][GET_MODE (inner)])); |
| } |
| |
| /* Return nonzero if IN can be reloaded into REGNO with mode MODE without |
| requiring an extra reload register. The caller has already found that |
| IN contains some reference to REGNO, so check that we can produce the |
| new value in a single step. E.g. if we have |
| (set (reg r13) (plus (reg r13) (const int 1))), and there is an |
| instruction that adds one to a register, this should succeed. |
| However, if we have something like |
| (set (reg r13) (plus (reg r13) (const int 999))), and the constant 999 |
| needs to be loaded into a register first, we need a separate reload |
| register. |
| Such PLUS reloads are generated by find_reload_address_part. |
| The out-of-range PLUS expressions are usually introduced in the instruction |
| patterns by register elimination and substituting pseudos without a home |
| by their function-invariant equivalences. */ |
| static int |
| can_reload_into (rtx in, int regno, machine_mode mode) |
| { |
| rtx dst; |
| rtx_insn *test_insn; |
| int r = 0; |
| struct recog_data_d save_recog_data; |
| |
| /* For matching constraints, we often get notional input reloads where |
| we want to use the original register as the reload register. I.e. |
| technically this is a non-optional input-output reload, but IN is |
| already a valid register, and has been chosen as the reload register. |
| Speed this up, since it trivially works. */ |
| if (REG_P (in)) |
| return 1; |
| |
| /* To test MEMs properly, we'd have to take into account all the reloads |
| that are already scheduled, which can become quite complicated. |
| And since we've already handled address reloads for this MEM, it |
| should always succeed anyway. */ |
| if (MEM_P (in)) |
| return 1; |
| |
| /* If we can make a simple SET insn that does the job, everything should |
| be fine. */ |
| dst = gen_rtx_REG (mode, regno); |
| test_insn = make_insn_raw (gen_rtx_SET (VOIDmode, dst, in)); |
| save_recog_data = recog_data; |
| if (recog_memoized (test_insn) >= 0) |
| { |
| extract_insn (test_insn); |
| r = constrain_operands (1, get_enabled_alternatives (test_insn)); |
| } |
| recog_data = save_recog_data; |
| return r; |
| } |
| |
| /* Record one reload that needs to be performed. |
| IN is an rtx saying where the data are to be found before this instruction. |
| OUT says where they must be stored after the instruction. |
| (IN is zero for data not read, and OUT is zero for data not written.) |
| INLOC and OUTLOC point to the places in the instructions where |
| IN and OUT were found. |
| If IN and OUT are both nonzero, it means the same register must be used |
| to reload both IN and OUT. |
| |
| RCLASS is a register class required for the reloaded data. |
| INMODE is the machine mode that the instruction requires |
| for the reg that replaces IN and OUTMODE is likewise for OUT. |
| |
| If IN is zero, then OUT's location and mode should be passed as |
| INLOC and INMODE. |
| |
| STRICT_LOW is the 1 if there is a containing STRICT_LOW_PART rtx. |
| |
| OPTIONAL nonzero means this reload does not need to be performed: |
| it can be discarded if that is more convenient. |
| |
| OPNUM and TYPE say what the purpose of this reload is. |
| |
| The return value is the reload-number for this reload. |
| |
| If both IN and OUT are nonzero, in some rare cases we might |
| want to make two separate reloads. (Actually we never do this now.) |
| Therefore, the reload-number for OUT is stored in |
| output_reloadnum when we return; the return value applies to IN. |
| Usually (presently always), when IN and OUT are nonzero, |
| the two reload-numbers are equal, but the caller should be careful to |
| distinguish them. */ |
| |
| int |
| push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, |
| enum reg_class rclass, machine_mode inmode, |
| machine_mode outmode, int strict_low, int optional, |
| int opnum, enum reload_type type) |
| { |
| int i; |
| int dont_share = 0; |
| int dont_remove_subreg = 0; |
| #ifdef LIMIT_RELOAD_CLASS |
| rtx *in_subreg_loc = 0, *out_subreg_loc = 0; |
| #endif |
| 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; |
| enum reg_class subreg_in_class ATTRIBUTE_UNUSED; |
| subreg_in_class = NO_REGS; |
| |
| /* 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 find_reloads and friends until now missed to replace a pseudo |
| with a constant of reg_equiv_constant something went wrong |
| beforehand. |
| Note that it can't simply be done here if we missed it earlier |
| since the constant might need to be pushed into the literal pool |
| and the resulting memref would probably need further |
| reloading. */ |
| if (in != 0 && REG_P (in)) |
| { |
| int regno = REGNO (in); |
| |
| gcc_assert (regno < FIRST_PSEUDO_REGISTER |
| || reg_renumber[regno] >= 0 |
| || reg_equiv_constant (regno) == NULL_RTX); |
| } |
| |
| /* reg_equiv_constant only contains constants which are obviously |
| not appropriate as destination. So if we would need to replace |
| the destination pseudo with a constant we are in real |
| trouble. */ |
| if (out != 0 && REG_P (out)) |
| { |
| int regno = REGNO (out); |
| |
| gcc_assert (regno < FIRST_PSEUDO_REGISTER |
| || reg_renumber[regno] >= 0 |
| || reg_equiv_constant (regno) == NULL_RTX); |
| } |
| |
| /* If we have a read-write operand with an address side-effect, |
| change either IN or OUT so the side-effect happens only once. */ |
| if (in != 0 && out != 0 && MEM_P (in) && rtx_equal_p (in, out)) |
| switch (GET_CODE (XEXP (in, 0))) |
| { |
| case POST_INC: case POST_DEC: case POST_MODIFY: |
| in = replace_equiv_address_nv (in, XEXP (XEXP (in, 0), 0)); |
| break; |
| |
| case PRE_INC: case PRE_DEC: case PRE_MODIFY: |
| out = replace_equiv_address_nv (out, XEXP (XEXP (out, 0), 0)); |
| break; |
| |
| default: |
| break; |
| } |
| |
| /* If we are reloading a (SUBREG constant ...), really reload just the |
| inside expression in its own mode. Similarly for (SUBREG (PLUS ...)). |
| If we have (SUBREG:M1 (MEM:M2 ...) ...) (or an inner REG that is still |
| a pseudo and hence will become a MEM) with M1 wider than M2 and the |
| register is a pseudo, also reload the inside expression. |
| For machines that extend byte loads, do this for any SUBREG of a pseudo |
| where both M1 and M2 are a word or smaller, M1 is wider than M2, and |
| M2 is an integral mode that gets extended when loaded. |
| Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R |
| where either M1 is not valid for R or M2 is wider than a word but we |
| only need one register 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 this case). |
| |
| Also reload the inner expression if it does not require a secondary |
| reload but the SUBREG does. |
| |
| Finally, reload the inner expression if it is a register that is in |
| the class whose registers cannot be referenced in a different size |
| and M1 is not the same size as M2. If subreg_lowpart_p is false, we |
| cannot reload just the inside since we might end up with the wrong |
| register class. But if it is inside a STRICT_LOW_PART, we have |
| no choice, so we hope we do get the right register class there. */ |
| |
| if (in != 0 && GET_CODE (in) == SUBREG |
| && (subreg_lowpart_p (in) || strict_low) |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, rclass) |
| #endif |
| && contains_reg_of_mode[(int) rclass][(int) GET_MODE (SUBREG_REG (in))] |
| && (CONSTANT_P (SUBREG_REG (in)) |
| || GET_CODE (SUBREG_REG (in)) == PLUS |
| || strict_low |
| || (((REG_P (SUBREG_REG (in)) |
| && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER) |
| || MEM_P (SUBREG_REG (in))) |
| && ((GET_MODE_PRECISION (inmode) |
| > GET_MODE_PRECISION (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_PRECISION (inmode) |
| > GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in)))) |
| && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in))) |
| && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != UNKNOWN) |
| #endif |
| #ifdef WORD_REGISTER_OPERATIONS |
| || ((GET_MODE_PRECISION (inmode) |
| < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in)))) |
| && ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD == |
| ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1) |
| / UNITS_PER_WORD))) |
| #endif |
| )) |
| || (REG_P (SUBREG_REG (in)) |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER |
| /* The case where out is nonzero |
| is handled differently in the following statement. */ |
| && (out == 0 || subreg_lowpart_p (in)) |
| && ((GET_MODE_SIZE (inmode) <= UNITS_PER_WORD |
| && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) |
| > UNITS_PER_WORD) |
| && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) |
| / UNITS_PER_WORD) |
| != (int) hard_regno_nregs[REGNO (SUBREG_REG (in))] |
| [GET_MODE (SUBREG_REG (in))])) |
| || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode))) |
| || (secondary_reload_class (1, rclass, inmode, in) != NO_REGS |
| && (secondary_reload_class (1, rclass, GET_MODE (SUBREG_REG (in)), |
| SUBREG_REG (in)) |
| == NO_REGS)) |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| || (REG_P (SUBREG_REG (in)) |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER |
| && REG_CANNOT_CHANGE_MODE_P |
| (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode)) |
| #endif |
| )) |
| { |
| #ifdef LIMIT_RELOAD_CLASS |
| in_subreg_loc = inloc; |
| #endif |
| inloc = &SUBREG_REG (in); |
| in = *inloc; |
| #if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) |
| if (MEM_P (in)) |
| /* This is supposed to happen only for paradoxical subregs made by |
| combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */ |
| gcc_assert (GET_MODE_SIZE (GET_MODE (in)) <= GET_MODE_SIZE (inmode)); |
| #endif |
| inmode = GET_MODE (in); |
| } |
| |
| /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R |
| where M1 is not valid for R if it was not handled by the code above. |
| |
| Similar issue for (SUBREG constant ...) if it was not handled by the |
| code above. This can happen if SUBREG_BYTE != 0. |
| |
| However, we must reload the inner reg *as well as* the subreg in |
| that case. */ |
| |
| if (in != 0 && reload_inner_reg_of_subreg (in, inmode, false)) |
| { |
| if (REG_P (SUBREG_REG (in))) |
| subreg_in_class |
| = find_valid_class (inmode, GET_MODE (SUBREG_REG (in)), |
| subreg_regno_offset (REGNO (SUBREG_REG (in)), |
| GET_MODE (SUBREG_REG (in)), |
| SUBREG_BYTE (in), |
| GET_MODE (in)), |
| REGNO (SUBREG_REG (in))); |
| else if (GET_CODE (SUBREG_REG (in)) == SYMBOL_REF) |
| subreg_in_class = find_valid_class_1 (inmode, |
| GET_MODE (SUBREG_REG (in)), |
| rclass); |
| |
| /* This relies on the fact that emit_reload_insns outputs the |
| instructions for input reloads of type RELOAD_OTHER in the same |
| order as the reloads. Thus if the outer reload is also of type |
| RELOAD_OTHER, we are guaranteed that this inner reload will be |
| output before the outer reload. */ |
| push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *) 0, |
| subreg_in_class, VOIDmode, VOIDmode, 0, 0, opnum, type); |
| dont_remove_subreg = 1; |
| } |
| |
| /* Similarly for paradoxical and problematical SUBREGs on the output. |
| Note that there is no reason we need worry about the previous value |
| of SUBREG_REG (out); even if wider than out, storing in a subreg is |
| entitled to clobber it all (except in the case of a word mode subreg |
| or of a STRICT_LOW_PART, in that latter case the constraint should |
| label it input-output.) */ |
| if (out != 0 && GET_CODE (out) == SUBREG |
| && (subreg_lowpart_p (out) || strict_low) |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, rclass) |
| #endif |
| && contains_reg_of_mode[(int) rclass][(int) GET_MODE (SUBREG_REG (out))] |
| && (CONSTANT_P (SUBREG_REG (out)) |
| || strict_low |
| || (((REG_P (SUBREG_REG (out)) |
| && REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER) |
| || MEM_P (SUBREG_REG (out))) |
| && ((GET_MODE_PRECISION (outmode) |
| > GET_MODE_PRECISION (GET_MODE (SUBREG_REG (out)))) |
| #ifdef WORD_REGISTER_OPERATIONS |
| || ((GET_MODE_PRECISION (outmode) |
| < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (out)))) |
| && ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD == |
| ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1) |
| / UNITS_PER_WORD))) |
| #endif |
| )) |
| || (REG_P (SUBREG_REG (out)) |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER |
| /* The case of a word mode subreg |
| is handled differently in the following statement. */ |
| && ! (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD |
| && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) |
| > UNITS_PER_WORD)) |
| && ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode)) |
| || (secondary_reload_class (0, rclass, outmode, out) != NO_REGS |
| && (secondary_reload_class (0, rclass, GET_MODE (SUBREG_REG (out)), |
| SUBREG_REG (out)) |
| == NO_REGS)) |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| || (REG_P (SUBREG_REG (out)) |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER |
| && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), |
| GET_MODE (SUBREG_REG (out)), |
| outmode)) |
| #endif |
| )) |
| { |
| #ifdef LIMIT_RELOAD_CLASS |
| out_subreg_loc = outloc; |
| #endif |
| outloc = &SUBREG_REG (out); |
| out = *outloc; |
| #if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS) |
| gcc_assert (!MEM_P (out) |
| || GET_MODE_SIZE (GET_MODE (out)) |
| <= GET_MODE_SIZE (outmode)); |
| #endif |
| outmode = GET_MODE (out); |
| } |
| |
| /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R |
| where either M1 is not valid for R or M2 is wider than a word but we |
| only need one register to store an M2-sized quantity in R. |
| |
| However, we must reload the inner reg *as well as* the subreg in |
| that case and the inner reg is an in-out reload. */ |
| |
| if (out != 0 && reload_inner_reg_of_subreg (out, outmode, true)) |
| { |
| enum reg_class in_out_class |
| = find_valid_class (outmode, GET_MODE (SUBREG_REG (out)), |
| subreg_regno_offset (REGNO (SUBREG_REG (out)), |
| GET_MODE (SUBREG_REG (out)), |
| SUBREG_BYTE (out), |
| GET_MODE (out)), |
| REGNO (SUBREG_REG (out))); |
| |
| /* 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. */ |
| push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out), |
| &SUBREG_REG (out), in_out_class, VOIDmode, VOIDmode, |
| 0, 0, opnum, RELOAD_OTHER); |
| dont_remove_subreg = 1; |
| } |
| |
| /* If IN appears in OUT, we can't share any input-only reload for IN. */ |
| if (in != 0 && out != 0 && MEM_P (out) |
| && (REG_P (in) || MEM_P (in) || GET_CODE (in) == PLUS) |
| && reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0))) |
| dont_share = 1; |
| |
| /* If IN is a SUBREG of a hard register, make a new REG. This |
| simplifies some of the cases below. */ |
| |
| if (in != 0 && GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)) |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER |
| && ! dont_remove_subreg) |
| in = gen_rtx_REG (GET_MODE (in), subreg_regno (in)); |
| |
| /* Similarly for OUT. */ |
| if (out != 0 && GET_CODE (out) == SUBREG |
| && REG_P (SUBREG_REG (out)) |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER |
| && ! dont_remove_subreg) |
| out = gen_rtx_REG (GET_MODE (out), subreg_regno (out)); |
| |
| /* Narrow down the class of register wanted if that is |
| desirable on this machine for efficiency. */ |
| { |
| reg_class_t preferred_class = rclass; |
| |
| if (in != 0) |
| preferred_class = targetm.preferred_reload_class (in, rclass); |
| |
| /* Output reloads may need analogous treatment, different in detail. */ |
| if (out != 0) |
| preferred_class |
| = targetm.preferred_output_reload_class (out, preferred_class); |
| |
| /* Discard what the target said if we cannot do it. */ |
| if (preferred_class != NO_REGS |
| || (optional && type == RELOAD_FOR_OUTPUT)) |
| rclass = (enum reg_class) preferred_class; |
| } |
| |
| /* Make sure we use a class that can handle the actual pseudo |
| inside any subreg. For example, on the 386, QImode regs |
| can appear within SImode subregs. Although GENERAL_REGS |
| can handle SImode, QImode needs a smaller class. */ |
| #ifdef LIMIT_RELOAD_CLASS |
| if (in_subreg_loc) |
| rclass = LIMIT_RELOAD_CLASS (inmode, rclass); |
| else if (in != 0 && GET_CODE (in) == SUBREG) |
| rclass = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), rclass); |
| |
| if (out_subreg_loc) |
| rclass = LIMIT_RELOAD_CLASS (outmode, rclass); |
| if (out != 0 && GET_CODE (out) == SUBREG) |
| rclass = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), rclass); |
| #endif |
| |
| /* Verify that this class is at least possible for the mode that |
| is specified. */ |
| if (this_insn_is_asm) |
| { |
| 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) |
| && in_hard_reg_set_p (reg_class_contents[(int) rclass], mode, i)) |
| break; |
| if (i == FIRST_PSEUDO_REGISTER) |
| { |
| error_for_asm (this_insn, "impossible register constraint " |
| "in %<asm%>"); |
| /* Avoid further trouble with this insn. */ |
| PATTERN (this_insn) = gen_rtx_USE (VOIDmode, const0_rtx); |
| /* We used to continue here setting class to ALL_REGS, but it triggers |
| sanity check on i386 for: |
| void foo(long double d) |
| { |
| asm("" :: "a" (d)); |
| } |
| Returning zero here ought to be safe as we take care in |
| find_reloads to not process the reloads when instruction was |
| replaced by USE. */ |
| |
| return 0; |
| } |
| } |
| |
| /* Optional output reloads are always OK even if we have no register class, |
| since the function of these reloads is only to have spill_reg_store etc. |
| set, so that the storing insn can be deleted later. */ |
| gcc_assert (rclass != NO_REGS |
| || (optional != 0 && type == RELOAD_FOR_OUTPUT)); |
| |
| i = find_reusable_reload (&in, out, rclass, type, opnum, dont_share); |
| |
| if (i == n_reloads) |
| { |
| /* See if we need a secondary reload register to move between CLASS |
| and IN or CLASS and OUT. Get the icode and push any required reloads |
| needed for each of them if so. */ |
| |
| if (in != 0) |
| secondary_in_reload |
| = push_secondary_reload (1, in, opnum, optional, rclass, inmode, type, |
| &secondary_in_icode, NULL); |
| if (out != 0 && GET_CODE (out) != SCRATCH) |
| secondary_out_reload |
| = push_secondary_reload (0, out, opnum, optional, rclass, outmode, |
| type, &secondary_out_icode, NULL); |
| |
| /* We found no existing reload suitable for re-use. |
| So add an additional reload. */ |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| if (subreg_in_class == NO_REGS |
| && in != 0 |
| && (REG_P (in) |
| || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)))) |
| && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER) |
| subreg_in_class = REGNO_REG_CLASS (reg_or_subregno (in)); |
| /* If a memory location is needed for the copy, make one. */ |
| if (subreg_in_class != NO_REGS |
| && SECONDARY_MEMORY_NEEDED (subreg_in_class, rclass, inmode)) |
| get_secondary_mem (in, inmode, opnum, type); |
| #endif |
| |
| i = n_reloads; |
| rld[i].in = in; |
| rld[i].out = out; |
| rld[i].rclass = rclass; |
| rld[i].inmode = inmode; |
| rld[i].outmode = outmode; |
| rld[i].reg_rtx = 0; |
| rld[i].optional = optional; |
| rld[i].inc = 0; |
| rld[i].nocombine = 0; |
| rld[i].in_reg = inloc ? *inloc : 0; |
| rld[i].out_reg = outloc ? *outloc : 0; |
| rld[i].opnum = opnum; |
| rld[i].when_needed = type; |
| rld[i].secondary_in_reload = secondary_in_reload; |
| rld[i].secondary_out_reload = secondary_out_reload; |
| rld[i].secondary_in_icode = secondary_in_icode; |
| rld[i].secondary_out_icode = secondary_out_icode; |
| rld[i].secondary_p = 0; |
| |
| n_reloads++; |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| if (out != 0 |
| && (REG_P (out) |
| || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out)))) |
| && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER |
| && SECONDARY_MEMORY_NEEDED (rclass, |
| REGNO_REG_CLASS (reg_or_subregno (out)), |
| outmode)) |
| get_secondary_mem (out, outmode, opnum, type); |
| #endif |
| } |
| else |
| { |
| /* We are reusing an existing reload, |
| but we may have additional information for it. |
| For example, we may now have both IN and OUT |
| while the old one may have just one of them. */ |
| |
| /* The modes can be different. If they are, we want to reload in |
| the larger mode, so that the value is valid for both modes. */ |
| if (inmode != VOIDmode |
| && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (rld[i].inmode)) |
| rld[i].inmode = inmode; |
| if (outmode != VOIDmode |
| && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (rld[i].outmode)) |
| rld[i].outmode = outmode; |
| if (in != 0) |
| { |
| rtx in_reg = inloc ? *inloc : 0; |
| /* If we merge reloads for two distinct rtl expressions that |
| are identical in content, there might be duplicate address |
| reloads. Remove the extra set now, so that if we later find |
| that we can inherit this reload, we can get rid of the |
| address reloads altogether. |
| |
| Do not do this if both reloads are optional since the result |
| would be an optional reload which could potentially leave |
| unresolved address replacements. |
| |
| It is not sufficient to call transfer_replacements since |
| choose_reload_regs will remove the replacements for address |
| reloads of inherited reloads which results in the same |
| problem. */ |
| if (rld[i].in != in && rtx_equal_p (in, rld[i].in) |
| && ! (rld[i].optional && optional)) |
| { |
| /* We must keep the address reload with the lower operand |
| number alive. */ |
| if (opnum > rld[i].opnum) |
| { |
| remove_address_replacements (in); |
| in = rld[i].in; |
| in_reg = rld[i].in_reg; |
| } |
| else |
| remove_address_replacements (rld[i].in); |
| } |
| /* When emitting reloads we don't necessarily look at the in- |
| and outmode, but also directly at the operands (in and out). |
| So we can't simply overwrite them with whatever we have found |
| for this (to-be-merged) reload, we have to "merge" that too. |
| Reusing another reload already verified that we deal with the |
| same operands, just possibly in different modes. So we |
| overwrite the operands only when the new mode is larger. |
| See also PR33613. */ |
| if (!rld[i].in |
| || GET_MODE_SIZE (GET_MODE (in)) |
| > GET_MODE_SIZE (GET_MODE (rld[i].in))) |
| rld[i].in = in; |
| if (!rld[i].in_reg |
| || (in_reg |
| && GET_MODE_SIZE (GET_MODE (in_reg)) |
| > GET_MODE_SIZE (GET_MODE (rld[i].in_reg)))) |
| rld[i].in_reg = in_reg; |
| } |
| if (out != 0) |
| { |
| if (!rld[i].out |
| || (out |
| && GET_MODE_SIZE (GET_MODE (out)) |
| > GET_MODE_SIZE (GET_MODE (rld[i].out)))) |
| rld[i].out = out; |
| if (outloc |
| && (!rld[i].out_reg |
| || GET_MODE_SIZE (GET_MODE (*outloc)) |
| > GET_MODE_SIZE (GET_MODE (rld[i].out_reg)))) |
| rld[i].out_reg = *outloc; |
| } |
| if (reg_class_subset_p (rclass, rld[i].rclass)) |
| rld[i].rclass = rclass; |
| rld[i].optional &= optional; |
| if (MERGE_TO_OTHER (type, rld[i].when_needed, |
| opnum, rld[i].opnum)) |
| rld[i].when_needed = RELOAD_OTHER; |
| rld[i].opnum = MIN (rld[i].opnum, opnum); |
| } |
| |
| /* If the ostensible rtx being reloaded differs from the rtx found |
| in the location to substitute, this reload is not safe to combine |
| because we cannot reliably tell whether it appears in the insn. */ |
| |
| if (in != 0 && in != *inloc) |
| rld[i].nocombine = 1; |
| |
| #if 0 |
| /* This was replaced by changes in find_reloads_address_1 and the new |
| function inc_for_reload, which go with a new meaning of reload_inc. */ |
| |
| /* If this is an IN/OUT reload in an insn that sets the CC, |
| it must be for an autoincrement. It doesn't work to store |
| the incremented value after the insn because that would clobber the CC. |
| So we must do the increment of the value reloaded from, |
| increment it, store it back, then decrement again. */ |
| if (out != 0 && sets_cc0_p (PATTERN (this_insn))) |
| { |
| out = 0; |
| rld[i].out = 0; |
| rld[i].inc = find_inc_amount (PATTERN (this_insn), in); |
| /* If we did not find a nonzero amount-to-increment-by, |
| that contradicts the belief that IN is being incremented |
| in an address in this insn. */ |
| gcc_assert (rld[i].inc != 0); |
| } |
| #endif |
| |
| /* If we will replace IN and OUT with the reload-reg, |
| record where they are located so that substitution need |
| not do a tree walk. */ |
| |
| if (replace_reloads) |
| { |
| if (inloc != 0) |
| { |
| struct replacement *r = &replacements[n_replacements++]; |
| r->what = i; |
| r->where = inloc; |
| r->mode = inmode; |
| } |
| if (outloc != 0 && outloc != inloc) |
| { |
| struct replacement *r = &replacements[n_replacements++]; |
| r->what = i; |
| r->where = outloc; |
| r->mode = outmode; |
| } |
| } |
| |
| /* If this reload is just being introduced and it has both |
| an incoming quantity and an outgoing quantity that are |
| supposed to be made to match, see if either one of the two |
| can serve as the place to reload into. |
| |
| If one of them is acceptable, set rld[i].reg_rtx |
| to that one. */ |
| |
| if (in != 0 && out != 0 && in != out && rld[i].reg_rtx == 0) |
| { |
| rld[i].reg_rtx = find_dummy_reload (in, out, inloc, outloc, |
| inmode, outmode, |
| rld[i].rclass, i, |
| earlyclobber_operand_p (out)); |
| |
| /* If the outgoing register already contains the same value |
| as the incoming one, we can dispense with loading it. |
| The easiest way to tell the caller that is to give a phony |
| value for the incoming operand (same as outgoing one). */ |
| if (rld[i].reg_rtx == out |
| && (REG_P (in) || CONSTANT_P (in)) |
| && 0 != find_equiv_reg (in, this_insn, NO_REGS, REGNO (out), |
| static_reload_reg_p, i, inmode)) |
| rld[i].in = out; |
| } |
| |
| /* If this is an input reload and the operand contains a register that |
| dies in this insn and is used nowhere else, see if it is the right class |
| to be used for this reload. Use it if so. (This occurs most commonly |
| in the case of paradoxical SUBREGs and in-out reloads). We cannot do |
| this if it is also an output reload that mentions the register unless |
| the output is a SUBREG that clobbers an entire register. |
| |
| Note that the operand might be one of the spill regs, if it is a |
| pseudo reg and we are in a block where spilling has not taken place. |
| But if there is no spilling in this block, that is OK. |
| An explicitly used hard reg cannot be a spill reg. */ |
| |
| if (rld[i].reg_rtx == 0 && in != 0 && hard_regs_live_known) |
| { |
| rtx note; |
| int regno; |
| machine_mode rel_mode = inmode; |
| |
| if (out && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (inmode)) |
| rel_mode = outmode; |
| |
| for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1)) |
| if (REG_NOTE_KIND (note) == REG_DEAD |
| && REG_P (XEXP (note, 0)) |
| && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER |
| && reg_mentioned_p (XEXP (note, 0), in) |
| /* Check that a former pseudo is valid; see find_dummy_reload. */ |
| && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER |
| || (! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)), |
| ORIGINAL_REGNO (XEXP (note, 0))) |
| && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1)) |
| && ! refers_to_regno_for_reload_p (regno, |
| end_hard_regno (rel_mode, |
| regno), |
| PATTERN (this_insn), inloc) |
| && ! find_reg_fusage (this_insn, USE, XEXP (note, 0)) |
| /* 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, |
| end_hard_regno (rel_mode, regno), |
| PATTERN (this_insn))) |
| /* ??? Why is this code so different from the previous? |
| Is there any simple coherent way to describe the two together? |
| What's going on here. */ |
| && (in != out |
| || (GET_CODE (in) == SUBREG |
| && (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1)) |
| / UNITS_PER_WORD) |
| == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) |
| + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))) |
| /* Make sure the operand fits in the reg that dies. */ |
| && (GET_MODE_SIZE (rel_mode) |
| <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))) |
| && HARD_REGNO_MODE_OK (regno, inmode) |
| && HARD_REGNO_MODE_OK (regno, outmode)) |
| { |
| unsigned int offs; |
| unsigned int nregs = MAX (hard_regno_nregs[regno][inmode], |
| hard_regno_nregs[regno][outmode]); |
| |
| for (offs = 0; offs < nregs; offs++) |
| if (fixed_regs[regno + offs] |
| || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], |
| regno + offs)) |
| break; |
| |
| if (offs == nregs |
| && (! (refers_to_regno_for_reload_p |
| (regno, end_hard_regno (inmode, regno), in, (rtx *) 0)) |
| || can_reload_into (in, regno, inmode))) |
| { |
| rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno); |
| break; |
| } |
| } |
| } |
| |
| if (out) |
| output_reloadnum = i; |
| |
| return i; |
| } |
| |
| /* Record an additional place we must replace a value |
| for which we have already recorded a reload. |
| RELOADNUM is the value returned by push_reload |
| when the reload was recorded. |
| This is used in insn patterns that use match_dup. */ |
| |
| static void |
| push_replacement (rtx *loc, int reloadnum, machine_mode mode) |
| { |
| if (replace_reloads) |
| { |
| struct replacement *r = &replacements[n_replacements++]; |
| r->what = reloadnum; |
| r->where = loc; |
| r->mode = mode; |
| } |
| } |
| |
| /* Duplicate any replacement we have recorded to apply at |
| location ORIG_LOC to also be performed at DUP_LOC. |
| This is used in insn patterns that use match_dup. */ |
| |
| static void |
| dup_replacements (rtx *dup_loc, rtx *orig_loc) |
| { |
| int i, n = n_replacements; |
| |
| for (i = 0; i < n; i++) |
| { |
| struct replacement *r = &replacements[i]; |
| if (r->where == orig_loc) |
| push_replacement (dup_loc, r->what, r->mode); |
| } |
| } |
| |
| /* Transfer all replacements that used to be in reload FROM to be in |
| reload TO. */ |
| |
| void |
| transfer_replacements (int to, int from) |
| { |
| int i; |
| |
| for (i = 0; i < n_replacements; i++) |
| if (replacements[i].what == from) |
| replacements[i].what = to; |
| } |
| |
| /* IN_RTX is the value loaded by a reload that we now decided to inherit, |
| or a subpart of it. If we have any replacements registered for IN_RTX, |
| cancel the reloads that were supposed to load them. |
| Return nonzero if we canceled any reloads. */ |
| int |
| remove_address_replacements (rtx in_rtx) |
| { |
| int i, j; |
| char reload_flags[MAX_RELOADS]; |
| int something_changed = 0; |
| |
| memset (reload_flags, 0, sizeof reload_flags); |
| for (i = 0, j = 0; i < n_replacements; i++) |
| { |
| if (loc_mentioned_in_p (replacements[i].where, in_rtx)) |
| reload_flags[replacements[i].what] |= 1; |
| else |
| { |
| replacements[j++] = replacements[i]; |
| reload_flags[replacements[i].what] |= 2; |
| } |
| } |
| /* Note that the following store must be done before the recursive calls. */ |
| n_replacements = j; |
| |
| for (i = n_reloads - 1; i >= 0; i--) |
| { |
| if (reload_flags[i] == 1) |
| { |
| deallocate_reload_reg (i); |
| remove_address_replacements (rld[i].in); |
| rld[i].in = 0; |
| something_changed = 1; |
| } |
| } |
| return something_changed; |
| } |
| |
| /* If there is only one output reload, and it is not for an earlyclobber |
| operand, try to combine it with a (logically unrelated) input reload |
| to reduce the number of reload registers needed. |
| |
| This is safe if the input reload does not appear in |
| the value being output-reloaded, because this implies |
| it is not needed any more once the original insn completes. |
| |
| If that doesn't work, see we can use any of the registers that |
| die in this insn as a reload register. We can if it is of the right |
| class and does not appear in the value being output-reloaded. */ |
| |
| static void |
| combine_reloads (void) |
| { |
| int i, regno; |
| int output_reload = -1; |
| int secondary_out = -1; |
| rtx note; |
| |
| /* Find the output reload; return unless there is exactly one |
| and that one is mandatory. */ |
| |
| for (i = 0; i < n_reloads; i++) |
| if (rld[i].out != 0) |
| { |
| if (output_reload >= 0) |
| return; |
| output_reload = i; |
| } |
| |
| if (output_reload < 0 || rld[output_reload].optional) |
| return; |
| |
| /* An input-output reload isn't combinable. */ |
| |
| if (rld[output_reload].in != 0) |
| return; |
| |
| /* If this reload is for an earlyclobber operand, we can't do anything. */ |
| if (earlyclobber_operand_p (rld[output_reload].out)) |
| return; |
| |
| /* If there is a reload for part of the address of this operand, we would |
| need to change it to RELOAD_FOR_OTHER_ADDRESS. But that would extend |
| its life to the point where doing this combine would not lower the |
| number of spill registers needed. */ |
| for (i = 0; i < n_reloads; i++) |
| if ((rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS |
| || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS) |
| && rld[i].opnum == rld[output_reload].opnum) |
| return; |
| |
| /* Check each input reload; can we combine it? */ |
| |
| for (i = 0; i < n_reloads; i++) |
| if (rld[i].in && ! rld[i].optional && ! rld[i].nocombine |
| /* Life span of this reload must not extend past main insn. */ |
| && rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS |
| && rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS |
| && rld[i].when_needed != RELOAD_OTHER |
| && (ira_reg_class_max_nregs [(int)rld[i].rclass][(int) rld[i].inmode] |
| == ira_reg_class_max_nregs [(int) rld[output_reload].rclass] |
| [(int) rld[output_reload].outmode]) |
| && rld[i].inc == 0 |
| && rld[i].reg_rtx == 0 |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* Don't combine two reloads with different secondary |
| memory locations. */ |
| && (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum] == 0 |
| || secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] == 0 |
| || rtx_equal_p (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum], |
| secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum])) |
| #endif |
| && (targetm.small_register_classes_for_mode_p (VOIDmode) |
| ? (rld[i].rclass == rld[output_reload].rclass) |
| : (reg_class_subset_p (rld[i].rclass, |
| rld[output_reload].rclass) |
| || reg_class_subset_p (rld[output_reload].rclass, |
| rld[i].rclass))) |
| && (MATCHES (rld[i].in, rld[output_reload].out) |
| /* Args reversed because the first arg seems to be |
| the one that we imagine being modified |
| while the second is the one that might be affected. */ |
| || (! reg_overlap_mentioned_for_reload_p (rld[output_reload].out, |
| rld[i].in) |
| /* However, if the input is a register that appears inside |
| the output, then we also can't share. |
| Imagine (set (mem (reg 69)) (plus (reg 69) ...)). |
| If the same reload reg is used for both reg 69 and the |
| result to be stored in memory, then that result |
| will clobber the address of the memory ref. */ |
| && ! (REG_P (rld[i].in) |
| && reg_overlap_mentioned_for_reload_p (rld[i].in, |
| rld[output_reload].out)))) |
| && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode, |
| rld[i].when_needed != RELOAD_FOR_INPUT) |
| && (reg_class_size[(int) rld[i].rclass] |
| || targetm.small_register_classes_for_mode_p (VOIDmode)) |
| /* We will allow making things slightly worse by combining an |
| input and an output, but no worse than that. */ |
| && (rld[i].when_needed == RELOAD_FOR_INPUT |
| || rld[i].when_needed == RELOAD_FOR_OUTPUT)) |
| { |
| int j; |
| |
| /* We have found a reload to combine with! */ |
| rld[i].out = rld[output_reload].out; |
| rld[i].out_reg = rld[output_reload].out_reg; |
| rld[i].outmode = rld[output_reload].outmode; |
| /* Mark the old output reload as inoperative. */ |
| rld[output_reload].out = 0; |
| /* The combined reload is needed for the entire insn. */ |
| rld[i].when_needed = RELOAD_OTHER; |
| /* If the output reload had a secondary reload, copy it. */ |
| if (rld[output_reload].secondary_out_reload != -1) |
| { |
| rld[i].secondary_out_reload |
| = rld[output_reload].secondary_out_reload; |
| rld[i].secondary_out_icode |
| = rld[output_reload].secondary_out_icode; |
| } |
| |
| #ifdef SECONDARY_MEMORY_NEEDED |
| /* Copy any secondary MEM. */ |
| if (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] != 0) |
| secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum] |
| = secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum]; |
| #endif |
| /* If required, minimize the register class. */ |
| if (reg_class_subset_p (rld[output_reload].rclass, |
| rld[i].rclass)) |
| rld[i].rclass = rld[output_reload].rclass; |
| |
| /* Transfer all replacements from the old reload to the combined. */ |
| for (j = 0; j < n_replacements; j++) |
| if (replacements[j].what == output_reload) |
| replacements[j].what = i; |
| |
| return; |
| } |
| |
| /* If this insn has only one operand that is modified or written (assumed |
| to be the first), it must be the one corresponding to this reload. It |
| is safe to use anything that dies in this insn for that output provided |
| that it does not occur in the output (we already know it isn't an |
| earlyclobber. If this is an asm insn, give up. */ |
| |
| if (INSN_CODE (this_insn) == -1) |
| return; |
| |
| for (i = 1; i < insn_data[INSN_CODE (this_insn)].n_operands; i++) |
| if (insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '=' |
| || insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '+') |
| return; |
| |
| /* See if some hard register that dies in this insn and is not used in |
| the output is the right class. Only works if the register we pick |
| up can fully hold our output reload. */ |
| for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1)) |
| if (REG_NOTE_KIND (note) == REG_DEAD |
| && REG_P (XEXP (note, 0)) |
| && !reg_overlap_mentioned_for_reload_p (XEXP (note, 0), |
| rld[output_reload].out) |
| && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER |
| && HARD_REGNO_MODE_OK (regno, rld[output_reload].outmode) |
| && TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].rclass], |
| regno) |
| && (hard_regno_nregs[regno][rld[output_reload].outmode] |
| <= hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))]) |
| /* Ensure that a secondary or tertiary reload for this output |
| won't want this register. */ |
| && ((secondary_out = rld[output_reload].secondary_out_reload) == -1 |
| || (!(TEST_HARD_REG_BIT |
| (reg_class_contents[(int) rld[secondary_out].rclass], regno)) |
| && ((secondary_out = rld[secondary_out].secondary_out_reload) == -1 |
| || !(TEST_HARD_REG_BIT |
| (reg_class_contents[(int) rld[secondary_out].rclass], |
| regno))))) |
| && !fixed_regs[regno] |
| /* Check that a former pseudo is valid; see find_dummy_reload. */ |
| && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER |
| || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)), |
| ORIGINAL_REGNO (XEXP (note, 0))) |
| && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1))) |
| { |
| rld[output_reload].reg_rtx |
| = gen_rtx_REG (rld[output_reload].outmode, regno); |
| 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. |
| RCLASS is the register class required for the reload. |
| |
| If FOR_REAL is >= 0, it is the number of the reload, |
| and in some cases when it can be discovered that OUT doesn't need |
| to be computed, clear out rld[FOR_REAL].out. |
| |
| If FOR_REAL is -1, this should not be done, because this call |
| is just to see if a register can be found, not to find and install it. |
| |
| EARLYCLOBBER is nonzero if OUT is an earlyclobber operand. This |
| puts an additional constraint on being able to use IN for OUT since |
| IN must not appear elsewhere in the insn (it is assumed that IN itself |
| is safe from the earlyclobber). */ |
| |
| static rtx |
| find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc, |
| machine_mode inmode, machine_mode outmode, |
| reg_class_t rclass, int for_real, int earlyclobber) |
| { |
| rtx in = real_in; |
| rtx out = real_out; |
| int in_offset = 0; |
| int out_offset = 0; |
| rtx value = 0; |
| |
| /* If operands exceed a word, we can't use either of them |
| unless they have the same size. */ |
| if (GET_MODE_SIZE (outmode) != GET_MODE_SIZE (inmode) |
| && (GET_MODE_SIZE (outmode) > UNITS_PER_WORD |
| || GET_MODE_SIZE (inmode) > UNITS_PER_WORD)) |
| return 0; |
| |
| /* Note that {in,out}_offset are needed only when 'in' or 'out' |
| respectively refers to a hard register. */ |
| |
| /* Find the inside of any subregs. */ |
| while (GET_CODE (out) == SUBREG) |
| { |
| if (REG_P (SUBREG_REG (out)) |
| && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER) |
| out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)), |
| GET_MODE (SUBREG_REG (out)), |
| SUBREG_BYTE (out), |
| GET_MODE (out)); |
| out = SUBREG_REG (out); |
| } |
| while (GET_CODE (in) == SUBREG) |
| { |
| if (REG_P (SUBREG_REG (in)) |
| && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER) |
| in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)), |
| GET_MODE (SUBREG_REG (in)), |
| SUBREG_BYTE (in), |
| GET_MODE (in)); |
| in = SUBREG_REG (in); |
| } |
| |
| /* Narrow down the reg class, the same way push_reload will; |
| otherwise we might find a dummy now, but push_reload won't. */ |
| { |
| reg_class_t preferred_class = targetm.preferred_reload_class (in, rclass); |
| if (preferred_class != NO_REGS) |
| rclass = (enum reg_class) preferred_class; |
| } |
| |
| /* See if OUT will do. */ |
| if (REG_P (out) |
| && REGNO (out) < FIRST_PSEUDO_REGISTER) |
| { |
| unsigned int regno = REGNO (out) + out_offset; |
| unsigned int nwords = hard_regno_nregs[regno][outmode]; |
| rtx saved_rtx; |
| |
| /* When we consider whether the insn uses OUT, |
| ignore references within IN. They don't prevent us |
| from copying IN into OUT, because those refs would |
| move into the insn that reloads IN. |
| |
| However, we only ignore IN in its role as this reload. |
| If the insn uses IN elsewhere and it contains OUT, |
| that counts. We can't be sure it's the "same" operand |
| so it might not go through this reload. |
| |
| We also need to avoid using OUT if it, or part of it, is a |
| fixed register. Modifying such registers, even transiently, |
| may have undefined effects on the machine, such as modifying |
| the stack pointer. */ |
| saved_rtx = *inloc; |
| *inloc = const0_rtx; |
| |
| if (regno < FIRST_PSEUDO_REGISTER |
| && HARD_REGNO_MODE_OK (regno, outmode) |
| && ! refers_to_regno_for_reload_p (regno, regno + nwords, |
| PATTERN (this_insn), outloc)) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < nwords; i++) |
| if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], |
| regno + i) |
| || fixed_regs[regno + i]) |
| break; |
| |
| if (i == nwords) |
| { |
| if (REG_P (real_out)) |
| 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 |
| && REG_P (in) |
| && 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)) |
| && (ORIGINAL_REGNO (in) < FIRST_PSEUDO_REGISTER |
| /* However only do this if we can be sure that this input |
| operand doesn't correspond with an uninitialized pseudo. |
| global can assign some hardreg to it that is the same as |
| the one assigned to a different, also live pseudo (as it |
| can ignore the conflict). We must never introduce writes |
| to such hardregs, as they would clobber the other live |
| pseudo. See PR 20973. */ |
| || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)), |
| ORIGINAL_REGNO (in)) |
| /* Similarly, only do this if we can be sure that the death |
| note is still valid. global can assign some hardreg to |
| the pseudo referenced in the note and simultaneously a |
| subword of this hardreg to a different, also live pseudo, |
| because only another subword of the hardreg is actually |
| used in the insn. This cannot happen if the pseudo has |
| been assigned exactly one hardreg. See PR 33732. */ |
| && hard_regno_nregs[REGNO (in)][GET_MODE (in)] == 1))) |
| { |
| unsigned int regno = REGNO (in) + in_offset; |
| unsigned int nwords = hard_regno_nregs[regno][inmode]; |
| |
| if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, (rtx*) 0) |
| && ! hard_reg_set_here_p (regno, regno + nwords, |
| PATTERN (this_insn)) |
| && (! earlyclobber |
| || ! refers_to_regno_for_reload_p (regno, regno + nwords, |
| PATTERN (this_insn), inloc))) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < nwords; i++) |
| if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], |
| regno + i)) |
| break; |
| |
| if (i == nwords) |
| { |
| /* If we were going to use OUT as the reload reg |
| and changed our mind, it means OUT is a dummy that |
| dies here. So don't bother copying value to it. */ |
| if (for_real >= 0 && value == real_out) |
| rld[for_real].out = 0; |
| if (REG_P (real_in)) |
| value = real_in; |
| else |
| value = gen_rtx_REG (inmode, regno); |
| } |
| } |
| } |
| |
| return value; |
| } |
| |
| /* This page contains subroutines used mainly for determining |
| whether the IN or an OUT of a reload can serve as the |
| reload register. */ |
| |
| /* Return 1 if X is an operand of an insn that is being earlyclobbered. */ |
| |
| int |
| earlyclobber_operand_p (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 (unsigned int beg_regno, unsigned int end_regno, rtx x) |
| { |
| if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) |
| { |
| rtx op0 = SET_DEST (x); |
| |
| while (GET_CODE (op0) == SUBREG) |
| op0 = SUBREG_REG (op0); |
| if (REG_P (op0)) |
| { |
| unsigned int r = REGNO (op0); |
| |
| /* See if this reg overlaps range under consideration. */ |
| if (r < end_regno |
| && end_hard_regno (GET_MODE (op0), r) > beg_regno) |
| return 1; |
| } |
| } |
| else if (GET_CODE (x) == PARALLEL) |
| { |
| int i = XVECLEN (x, 0) - 1; |
| |
| for (; i >= 0; i--) |
| if (hard_reg_set_here_p (beg_regno, end_regno, XVECEXP (x, 0, i))) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* Return 1 if ADDR is a valid memory address for mode MODE |
| in address space AS, and check that each pseudo reg has the |
| proper kind of hard reg. */ |
| |
| int |
| strict_memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED, |
| rtx addr, addr_space_t as) |
| { |
| #ifdef GO_IF_LEGITIMATE_ADDRESS |
| gcc_assert (ADDR_SPACE_GENERIC_P (as)); |
| GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); |
| return 0; |
| |
| win: |
| return 1; |
| #else |
| return targetm.addr_space.legitimate_address_p (mode, addr, 1, as); |
| #endif |
| } |
| |
| /* 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 (rtx x, rtx y) |
| { |
| int i; |
| RTX_CODE code = GET_CODE (x); |
| const char *fmt; |
| int success_2; |
| |
| if (x == y) |
| return 1; |
| if ((code == REG || (code == SUBREG && REG_P (SUBREG_REG (x)))) |
| && (REG_P (y) || (GET_CODE (y) == SUBREG |
| && REG_P (SUBREG_REG (y))))) |
| { |
| int j; |
| |
| if (code == SUBREG) |
| { |
| i = REGNO (SUBREG_REG (x)); |
| if (i >= FIRST_PSEUDO_REGISTER) |
| goto slow; |
| i += subreg_regno_offset (REGNO (SUBREG_REG (x)), |
| GET_MODE (SUBREG_REG (x)), |
| SUBREG_BYTE (x), |
| GET_MODE (x)); |
| } |
| else |
| i = REGNO (x); |
| |
| if (GET_CODE (y) == SUBREG) |
| { |
| j = REGNO (SUBREG_REG (y)); |
| if (j >= FIRST_PSEUDO_REGISTER) |
| goto slow; |
| j += subreg_regno_offset (REGNO (SUBREG_REG (y)), |
| GET_MODE (SUBREG_REG (y)), |
| SUBREG_BYTE (y), |
| GET_MODE (y)); |
| } |
| else |
| j = REGNO (y); |
| |
| /* On a REG_WORDS_BIG_ENDIAN machine, point to the last register of a |
| multiple hard register group of scalar integer registers, so that |
| for example (reg:DI 0) and (reg:SI 1) will be considered the same |
| register. */ |
| if (REG_WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD |
| && SCALAR_INT_MODE_P (GET_MODE (x)) |
| && i < FIRST_PSEUDO_REGISTER) |
| i += hard_regno_nregs[i][GET_MODE (x)] - 1; |
| if (REG_WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD |
| && SCALAR_INT_MODE_P (GET_MODE (y)) |
| && j < FIRST_PSEUDO_REGISTER) |
| j += hard_regno_nregs[j][GET_MODE (y)] - 1; |
| |
| return i == j; |
| } |
| /* If two operands must match, because they are really a single |
| operand of an assembler insn, then two postincrements are invalid |
| because the assembler insn would increment only once. |
| On the other hand, a postincrement matches ordinary indexing |
| if the postincrement is the output operand. */ |
| if (code == POST_DEC || code == POST_INC || code == POST_MODIFY) |
| return operands_match_p (XEXP (x, 0), y); |
| /* Two preincrements are invalid |
| because the assembler insn would increment only once. |
| On the other hand, a preincrement matches ordinary indexing |
| if the preincrement is the input operand. |
| In this case, return 2, since some callers need to do special |
| things when this happens. */ |
| if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC |
| || GET_CODE (y) == PRE_MODIFY) |
| return operands_match_p (x, XEXP (y, 0)) ? 2 : 0; |
| |
| slow: |
| |
| /* Now we have disposed of all the cases in which different rtx codes |
| can match. */ |
| if (code != GET_CODE (y)) |
| return 0; |
| |
| /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ |
| if (GET_MODE (x) != GET_MODE (y)) |
| return 0; |
| |
| /* MEMs referring to different address space are not equivalent. */ |
| if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) |
| return 0; |
| |
| switch (code) |
| { |
| CASE_CONST_UNIQUE: |
| return 0; |
| |
| case LABEL_REF: |
| return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y); |
| case SYMBOL_REF: |
| return XSTR (x, 0) == XSTR (y, 0); |
| |
| default: |
| break; |
| } |
| |
| /* Compare the elements. If any pair of corresponding elements |
| fail to match, return 0 for the whole things. */ |
| |
| success_2 = 0; |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| { |
| int val, j; |
| switch (fmt[i]) |
| { |
| case 'w': |
| if (XWINT (x, i) != XWINT (y, i)) |
| return 0; |
| break; |
| |
| case 'i': |
| if (XINT (x, i) != XINT (y, i)) |
| return 0; |
| break; |
| |
| case 'e': |
| val = operands_match_p (XEXP (x, i), XEXP (y, i)); |
| if (val == 0) |
| return 0; |
| /* If any subexpression returns 2, |
| we should return 2 if we are successful. */ |
| if (val == 2) |
| success_2 = 1; |
| break; |
| |
| case '0': |
| break; |
| |
| case 'E': |
| if (XVECLEN (x, i) != XVECLEN (y, i)) |
| return 0; |
| for (j = XVECLEN (x, i) - 1; j >= 0; --j) |
| { |
| val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j)); |
| if (val == 0) |
| return 0; |
| if (val == 2) |
| success_2 = 1; |
| } |
| break; |
| |
| /* It is believed that rtx's at this level will never |
| contain anything but integers and other rtx's, |
| except for within LABEL_REFs and SYMBOL_REFs. */ |
| default: |
| gcc_unreachable (); |
| } |
| } |
| return 1 + success_2; |
| } |
| |
| /* Describe the range of registers or memory referenced by X. |
| If X is a register, set REG_FLAG and put the first register |
| number into START and the last plus one into END. |
| If X is a memory reference, put a base address into BASE |
| and a range of integer offsets into START and END. |
| If X is pushing on the stack, we can assume it causes no trouble, |
| so we set the SAFE field. */ |
| |
| static struct decomposition |
| decompose (rtx x) |
| { |
| struct decomposition val; |
| int all_const = 0; |
| |
| memset (&val, 0, sizeof (val)); |
| |
| switch (GET_CODE (x)) |
| { |
| case MEM: |
| { |
| rtx base = NULL_RTX, offset = 0; |
| rtx addr = XEXP (x, 0); |
| |
| if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC |
| || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC) |
| { |
| val.base = XEXP (addr, 0); |
| val.start = -GET_MODE_SIZE (GET_MODE (x)); |
| val.end = GET_MODE_SIZE (GET_MODE (x)); |
| val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; |
| return val; |
| } |
| |
| if (GET_CODE (addr) == PRE_MODIFY || GET_CODE (addr) == POST_MODIFY) |
| { |
| if (GET_CODE (XEXP (addr, 1)) == PLUS |
| && XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0) |
| && CONSTANT_P (XEXP (XEXP (addr, 1), 1))) |
| { |
| val.base = XEXP (addr, 0); |
| val.start = -INTVAL (XEXP (XEXP (addr, 1), 1)); |
| val.end = INTVAL (XEXP (XEXP (addr, 1), 1)); |
| val.safe = REGNO (val.base) == STACK_POINTER_REGNUM; |
| return val; |
| } |
| } |
| |
| if (GET_CODE (addr) == CONST) |
| { |
| addr = XEXP (addr, 0); |
| all_const = 1; |
| } |
| if (GET_CODE (addr) == PLUS) |
| { |
| if (CONSTANT_P (XEXP (addr, 0))) |
| { |
| base = XEXP (addr, 1); |
| offset = XEXP (addr, 0); |
| } |
| else if (CONSTANT_P (XEXP (addr, 1))) |
| { |
| base = XEXP (addr, 0); |
| offset = XEXP (addr, 1); |
| } |
| } |
| |
| if (offset == 0) |
| { |
| base = addr; |
| offset = const0_rtx; |
| } |
| if (GET_CODE (offset) == CONST) |
| offset = XEXP (offset, 0); |
| if (GET_CODE (offset) == PLUS) |
| { |
| if (CONST_INT_P (XEXP (offset, 0))) |
| { |
| base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1)); |
| offset = XEXP (offset, 0); |
| } |
| else if (CONST_INT_P (XEXP (offset, 1))) |
| { |
| 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 (!CONST_INT_P (offset)) |
| { |
| 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); |
| |
| gcc_assert (CONST_INT_P (offset)); |
| |
| val.start = INTVAL (offset); |
| val.end = val.start + GET_MODE_SIZE (GET_MODE (x)); |
| val.base = base; |
| } |
| break; |
| |
| case REG: |
| val.reg_flag = 1; |
| val.start = true_regnum (x); |
| if (val.start < 0 || val.start >= FIRST_PSEUDO_REGISTER) |
| { |
| /* A pseudo with no hard reg. */ |
| val.start = REGNO (x); |
| val.end = val.start + 1; |
| } |
| else |
| /* A hard reg. */ |
| val.end = end_hard_regno (GET_MODE (x), val.start); |
| break; |
| |
| case SUBREG: |
| if (!REG_P (SUBREG_REG (x))) |
| /* 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 || val.start >= FIRST_PSEUDO_REGISTER) |
| return decompose (SUBREG_REG (x)); |
| else |
| /* A hard reg. */ |
| val.end = val.start + subreg_nregs (x); |
| break; |
| |
| case SCRATCH: |
| /* This hasn't been assigned yet, so it can't conflict yet. */ |
| val.safe = 1; |
| break; |
| |
| default: |
| gcc_assert (CONSTANT_P (x)); |
| val.safe = 1; |
| break; |
| } |
| 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 (rtx x, rtx y, struct decomposition ydata) |
| { |
| struct decomposition xdata; |
| |
| if (ydata.reg_flag) |
| return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, (rtx*) 0); |
| if (ydata.safe) |
| return 1; |
| |
| gcc_assert (MEM_P (y)); |
| /* If Y is memory and X is not, Y can't affect X. */ |
| if (!MEM_P (x)) |
| 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 (rtx op, rtx clobber) |
| { |
| struct decomposition early_data; |
| |
| early_data = decompose (clobber); |
| return immune_p (op, clobber, early_data); |
| } |
| |
| /* Main entry point of this file: search the body of INSN |
| for values that need reloading and record them with push_reload. |
| REPLACE nonzero means record also where the values occur |
| so that subst_reloads can be used. |
| |
| IND_LEVELS says how many levels of indirection are supported by this |
| machine; a value of zero means that a memory reference is not a valid |
| memory address. |
| |
| LIVE_KNOWN says we have valid information about which hard |
| regs are live at each point in the program; this is true when |
| we are called from global_alloc but false when stupid register |
| allocation has been done. |
| |
| RELOAD_REG_P if nonzero is a vector indexed by hard reg number |
| which is nonnegative if the reg has been commandeered for reloading into. |
| It is copied into STATIC_RELOAD_REG_P and referenced from there |
| by various subroutines. |
| |
| Return TRUE if some operands need to be changed, because of swapping |
| commutative operands, reg_equiv_address substitution, or whatever. */ |
| |
| int |
| find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known, |
| short *reload_reg_p) |
| { |
| int insn_code_number; |
| int i, j; |
| int noperands; |
| /* These start out as the constraints for the insn |
| and they are chewed up as we consider alternatives. */ |
| const 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. |
| May be -1 to indicate the entire address may or may not need a reload. */ |
| int address_reloaded[MAX_RECOG_OPERANDS]; |
| /* Nonzero for an address operand that needs to be completely reloaded. |
| May be -1 to indicate the entire operand may or may not need a reload. */ |
| int address_operand_reloaded[MAX_RECOG_OPERANDS]; |
| /* Value of enum reload_type to use for operand. */ |
| enum reload_type operand_type[MAX_RECOG_OPERANDS]; |
| /* Value of enum reload_type to use within address of operand. */ |
| enum reload_type address_type[MAX_RECOG_OPERANDS]; |
| /* Save the usage of each operand. */ |
| enum reload_usage { RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE } modified[MAX_RECOG_OPERANDS]; |
| int no_input_reloads = 0, no_output_reloads = 0; |
| int n_alternatives; |
| reg_class_t this_alternative[MAX_RECOG_OPERANDS]; |
| char this_alternative_match_win[MAX_RECOG_OPERANDS]; |
| char this_alternative_win[MAX_RECOG_OPERANDS]; |
| char this_alternative_offmemok[MAX_RECOG_OPERANDS]; |
| char this_alternative_earlyclobber[MAX_RECOG_OPERANDS]; |
| int this_alternative_matches[MAX_RECOG_OPERANDS]; |
| reg_class_t goal_alternative[MAX_RECOG_OPERANDS]; |
| int this_alternative_number; |
| int goal_alternative_number = 0; |
| int operand_reloadnum[MAX_RECOG_OPERANDS]; |
| int goal_alternative_matches[MAX_RECOG_OPERANDS]; |
| int goal_alternative_matched[MAX_RECOG_OPERANDS]; |
| char goal_alternative_match_win[MAX_RECOG_OPERANDS]; |
| char goal_alternative_win[MAX_RECOG_OPERANDS]; |
| char goal_alternative_offmemok[MAX_RECOG_OPERANDS]; |
| char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS]; |
| int goal_alternative_swapped; |
| int best; |
| int commutative; |
| char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS]; |
| rtx substed_operand[MAX_RECOG_OPERANDS]; |
| rtx body = PATTERN (insn); |
| rtx set = single_set (insn); |
| int goal_earlyclobber = 0, this_earlyclobber; |
| machine_mode operand_mode[MAX_RECOG_OPERANDS]; |
| int retval = 0; |
| |
| this_insn = insn; |
| n_reloads = 0; |
| n_replacements = 0; |
| n_earlyclobbers = 0; |
| replace_reloads = replace; |
| hard_regs_live_known = live_known; |
| static_reload_reg_p = reload_reg_p; |
| |
| /* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads; |
| neither are insns that SET cc0. Insns that use CC0 are not allowed |
| to have any input reloads. */ |
| if (JUMP_P (insn) || CALL_P (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. */ |
| |
| if (secondary_memlocs_elim_used) |
| { |
| memset (secondary_memlocs_elim, 0, |
| sizeof (secondary_memlocs_elim[0]) * secondary_memlocs_elim_used); |
| secondary_memlocs_elim_used = 0; |
| } |
| #endif |
| |
| /* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it |
| is cheap to move between them. If it is not, there may not be an insn |
| to do the copy, so we may need a reload. */ |
| if (GET_CODE (body) == SET |
| && REG_P (SET_DEST (body)) |
| && REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER |
| && REG_P (SET_SRC (body)) |
| && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER |
| && register_move_cost (GET_MODE (SET_SRC (body)), |
| REGNO_REG_CLASS (REGNO (SET_SRC (body))), |
| REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2) |
| return 0; |
| |
| extract_insn (insn); |
| |
| noperands = reload_n_operands = recog_data.n_operands; |
| n_alternatives = recog_data.n_alternatives; |
| |
| /* Just return "no reloads" if insn has no operands with constraints. */ |
| if (noperands == 0 || n_alternatives == 0) |
| return 0; |
| |
| insn_code_number = INSN_CODE (insn); |
| this_insn_is_asm = insn_code_number < 0; |
| |
| memcpy (operand_mode, recog_data.operand_mode, |
| noperands * sizeof (machine_mode)); |
| memcpy (constraints, recog_data.constraints, |
| noperands * sizeof (const char *)); |
| |
| commutative = -1; |
| |
| /* If we will need to know, later, whether some pair of operands |
| are the same, we must compare them now and save the result. |
| Reloading the base and index registers will clobber them |
| and afterward they will fail to match. */ |
| |
| for (i = 0; i < noperands; i++) |
| { |
| const char *p; |
| int c; |
| char *end; |
| |
| substed_operand[i] = recog_data.operand[i]; |
| p = constraints[i]; |
| |
| modified[i] = RELOAD_READ; |
| |
| /* Scan this operand's constraint to see if it is an output operand, |
| an in-out operand, is commutative, or should match another. */ |
| |
| while ((c = *p)) |
| { |
| p += CONSTRAINT_LEN (c, p); |
| switch (c) |
| { |
| case '=': |
| modified[i] = RELOAD_WRITE; |
| break; |
| case '+': |
| modified[i] = RELOAD_READ_WRITE; |
| break; |
| case '%': |
| { |
| /* The last operand should not be marked commutative. */ |
| gcc_assert (i != noperands - 1); |
| |
| /* We currently only support one commutative pair of |
| operands. Some existing asm code currently uses more |
| than one pair. Previously, that would usually work, |
| but sometimes it would crash the compiler. We |
| continue supporting that case as well as we can by |
| silently ignoring all but the first pair. In the |
| future we may handle it correctly. */ |
| if (commutative < 0) |
| commutative = i; |
| else |
| gcc_assert (this_insn_is_asm); |
| } |
| break; |
| /* Use of ISDIGIT is tempting here, but it may get expensive because |
| of locale support we don't want. */ |
| case '0': case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': case '8': case '9': |
| { |
| c = strtoul (p - 1, &end, 10); |
| p = end; |
| |
| operands_match[c][i] |
| = operands_match_p (recog_data.operand[c], |
| recog_data.operand[i]); |
| |
| /* An operand may not match itself. */ |
| gcc_assert (c != i); |
| |
| /* If C can be commuted with C+1, and C might need to match I, |
| then C+1 might also need to match I. */ |
| if (commutative >= 0) |
| { |
| if (c == commutative || c == commutative + 1) |
| { |
| int other = c + (c == commutative ? 1 : -1); |
| operands_match[other][i] |
| = operands_match_p (recog_data.operand[other], |
| recog_data.operand[i]); |
| } |
| if (i == commutative || i == commutative + 1) |
| { |
| int other = i + (i == commutative ? 1 : -1); |
| operands_match[c][other] |
| = operands_match_p (recog_data.operand[c], |
| recog_data.operand[other]); |
| } |
| /* Note that C is supposed to be less than I. |
| No need to consider altering both C and I because in |
| that case we would alter one into the other. */ |
| } |
| } |
| } |
| } |
| } |
| |
| /* Examine each operand that is a memory reference or memory address |
| and reload parts of the addresses into index registers. |
| Also here any references to pseudo regs that didn't get hard regs |
| but are equivalent to constants get replaced in the insn itself |
| with those constants. Nobody will ever see them again. |
| |
| Finally, set up the preferred classes of each operand. */ |
| |
| for (i = 0; i < noperands; i++) |
| { |
| RTX_CODE code = GET_CODE (recog_data.operand[i]); |
| |
| address_reloaded[i] = 0; |
| address_operand_reloaded[i] = 0; |
| operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT |
| : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT |
| : RELOAD_OTHER); |
| address_type[i] |
| = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT_ADDRESS |
| : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT_ADDRESS |
| : RELOAD_OTHER); |
| |
| if (*constraints[i] == 0) |
| /* Ignore things like match_operator operands. */ |
| ; |
| else if (insn_extra_address_constraint |
| (lookup_constraint (constraints[i]))) |
| { |
| address_operand_reloaded[i] |
| = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0, |
| recog_data.operand[i], |
| recog_data.operand_loc[i], |
| i, operand_type[i], ind_levels, insn); |
| |
| /* If we now have a simple operand where we used to have a |
| PLUS or MULT, re-recognize and try again. */ |
| if ((OBJECT_P (*recog_data.operand_loc[i]) |
| || GET_CODE (*recog_data.operand_loc[i]) == SUBREG) |
| && (GET_CODE (recog_data.operand[i]) == MULT |
| || GET_CODE (recog_data.operand[i]) == PLUS)) |
| { |
| INSN_CODE (insn) = -1; |
| retval = find_reloads (insn, replace, ind_levels, live_known, |
| reload_reg_p); |
| return retval; |
| } |
| |
| recog_data.operand[i] = *recog_data.operand_loc[i]; |
| substed_operand[i] = recog_data.operand[i]; |
| |
| /* Address operands are reloaded in their existing mode, |
| no matter what is specified in the machine description. */ |
| operand_mode[i] = GET_MODE (recog_data.operand[i]); |
| |
| /* If the address is a single CONST_INT pick address mode |
| instead otherwise we will later not know in which mode |
| the reload should be performed. */ |
| if (operand_mode[i] == VOIDmode) |
| operand_mode[i] = Pmode; |
| |
| } |
| else if (code == MEM) |
| { |
| address_reloaded[i] |
| = find_reloads_address (GET_MODE (recog_data.operand[i]), |
| recog_data.operand_loc[i], |
| XEXP (recog_data.operand[i], 0), |
| &XEXP (recog_data.operand[i], 0), |
| i, address_type[i], ind_levels, insn); |
| recog_data.operand[i] = *recog_data.operand_loc[i]; |
| substed_operand[i] = recog_data.operand[i]; |
| } |
| else if (code == SUBREG) |
| { |
| rtx reg = SUBREG_REG (recog_data.operand[i]); |
| rtx op |
| = find_reloads_toplev (recog_data.operand[i], i, address_type[i], |
| ind_levels, |
| set != 0 |
| && &SET_DEST (set) == recog_data.operand_loc[i], |
| insn, |
| &address_reloaded[i]); |
| |
| /* If we made a MEM to load (a part of) the stackslot of a pseudo |
| that didn't get a hard register, emit a USE with a REG_EQUAL |
| note in front so that we might inherit a previous, possibly |
| wider reload. */ |
| |
| if (replace |
| && MEM_P (op) |
| && REG_P (reg) |
| && (GET_MODE_SIZE (GET_MODE (reg)) |
| >= GET_MODE_SIZE (GET_MODE (op))) |
| && reg_equiv_constant (REGNO (reg)) == 0) |
| set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg), |
| insn), |
| REG_EQUAL, reg_equiv_memory_loc (REGNO (reg))); |
| |
| substed_operand[i] = recog_data.operand[i] = op; |
| } |
| else if (code == PLUS || GET_RTX_CLASS (code) == RTX_UNARY) |
| /* We can get a PLUS as an "operand" as a result of register |
| elimination. See eliminate_regs and gen_reload. We handle |
| a unary operator by reloading the operand. */ |
| substed_operand[i] = recog_data.operand[i] |
| = find_reloads_toplev (recog_data.operand[i], i, address_type[i], |
| ind_levels, 0, insn, |
| &address_reloaded[i]); |
| else if (code == REG) |
| { |
| /* This is equivalent to calling find_reloads_toplev. |
| The code is duplicated for speed. |
| When we find a pseudo always equivalent to a constant, |
| we replace it by the constant. We must be sure, however, |
| that we don't try to replace it in the insn in which it |
| is being set. */ |
| int regno = REGNO (recog_data.operand[i]); |
| if (reg_equiv_constant (regno) != 0 |
| && (set == 0 || &SET_DEST (set) != recog_data.operand_loc[i])) |
| { |
| /* Record the existing mode so that the check if constants are |
| allowed will work when operand_mode isn't specified. */ |
| |
| if (operand_mode[i] == VOIDmode) |
| operand_mode[i] = GET_MODE (recog_data.operand[i]); |
| |
| substed_operand[i] = recog_data.operand[i] |
| = reg_equiv_constant (regno); |
| } |
| if (reg_equiv_memory_loc (regno) != 0 |
| && (reg_equiv_address (regno) != 0 || num_not_at_initial_offset)) |
| /* We need not give a valid is_set_dest argument since the case |
| of a constant equivalence was checked above. */ |
| substed_operand[i] = recog_data.operand[i] |
| = find_reloads_toplev (recog_data.operand[i], i, address_type[i], |
| ind_levels, 0, insn, |
| &address_reloaded[i]); |
| } |
| /* If the operand is still a register (we didn't replace it with an |
| equivalent), get the preferred class to reload it into. */ |
| code = GET_CODE (recog_data.operand[i]); |
| preferred_class[i] |
| = ((code == REG && REGNO (recog_data.operand[i |