diff options
author | vmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-10-23 15:51:41 +0000 |
---|---|---|
committer | vmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-10-23 15:51:41 +0000 |
commit | c6a6cdaaea571860c94f9a9fe0f98c597fef7c81 (patch) | |
tree | 915ce489d01a05653371ff4f7770258ffacab1b4 /gcc/lra-constraints.c | |
parent | d9459f6b9e27edcf999b5c06b87e21f8f24fd26f (diff) | |
download | gcc-c6a6cdaaea571860c94f9a9fe0f98c597fef7c81.tar.gz |
2012-10-23 Vladimir Makarov <vmakarov@redhat.com>
* dbxout.c (dbxout_symbol_location): Pass new argument to
alter_subreg.
* dwarf2out.c: Include ira.h and lra.h.
(based_loc_descr, compute_frame_pointer_to_fb_displacement): Use
lra_eliminate_regs for LRA instead of eliminate_regs.
* expr.c (emit_move_insn_1): Pass an additional argument to
emit_move_via_integer. Use emit_move_via_integer for LRA only if
the insn is recognized.
* emit-rtl.c (gen_rtx_REG): Add lra_in_progress.
(validate_subreg): Don't check offset for LRA and floating point
modes.
* final.c (final_scan_insn, cleanup_subreg_operands): Pass new
argument to alter_subreg.
(walk_alter_subreg, output_operand): Ditto.
(alter_subreg): Add new argument.
* gcse.c (calculate_bb_reg_pressure): Add parameter to
ira_setup_eliminable_regset call.
* ira.c: Include lra.h.
(ira_init_once, ira_init, ira_finish_once): Call lra_start_once,
lra_init, lra_finish_once in anyway.
(ira_setup_eliminable_regset): Add parameter. Remove need_fp.
Call lra_init_elimination and mark HARD_FRAME_POINTER_REGNUM as
living forever if frame_pointer_needed.
(setup_reg_class_relations): Set up ira_reg_class_subset.
(ira_reg_equiv_invariant_p, ira_reg_equiv_const): Remove.
(find_reg_equiv_invariant_const): Ditto.
(setup_reg_renumber): Use ira_equiv_no_lvalue_p instead of
ira_reg_equiv_invariant_p. Skip caps for LRA.
(setup_reg_equiv_init, ira_update_equiv_info_by_shuffle_insn): New
functions.
(ira_reg_equiv_len, ira_reg_equiv): New externals.
(ira_reg_equiv): New.
(ira_expand_reg_equiv, init_reg_equiv, finish_reg_equiv): New
functions.
(no_equiv, update_equiv_regs): Use ira_reg_equiv instead of
reg_equiv_init.
(setup_reg_equiv): New function.
(ira_use_lra_p): New global.
(ira): Set up lra_simple_p and ira_conflicts_p. Set up and
restore flag_caller_saves and flag_ira_region. Move
initialization of ira_obstack and ira_bitmap_obstack upper. Call
init_reg_equiv, setup_reg_equiv, and setup_reg_equiv_init instead
of initialization of ira_reg_equiv_len, ira_reg_equiv_invariant_p,
and ira_reg_equiv_const. Call ira_setup_eliminable_regset with a
new argument. Don't flatten IRA IRA for LRA. Don't reassign
conflict allocnos for LRA. Call finish_reg_equiv.
(do_reload): Prepare code for LRA call. Call LRA.
* ira.h (ira_use_lra_p): New external.
(struct target_ira): Add members x_ira_class_subset_p
x_ira_reg_class_subset, and x_ira_reg_classes_intersect_p.
(ira_class_subset_p, ira_reg_class_subset): New macros.
(ira_reg_classes_intersect_p): New macro.
(struct ira_reg_equiv): New.
(ira_setup_eliminable_regset): Add an argument.
(ira_expand_reg_equiv, ira_update_equiv_info_by_shuffle_insn): New
prototypes.
* ira-color.c (color_pass, move_spill_restore, coalesce_allocnos):
Use ira_equiv_no_lvalue_p.
(coalesce_spill_slots, ira_sort_regnos_for_alter_reg): Ditto.
* ira-emit.c (ira_create_new_reg): Call ira_expand_reg_equiv.
(generate_edge_moves, change_loop) Use ira_equiv_no_lvalue_p.
(emit_move_list): Simplify code. Call
ira_update_equiv_info_by_shuffle_insn. Use ira_reg_equiv instead
of ira_reg_equiv_invariant_p and ira_reg_equiv_const. Change
assert.
* ira-int.h (struct target_ira_int): Remove x_ira_class_subset_p
and x_ira_reg_classes_intersect_p.
(ira_class_subset_p, ira_reg_classes_intersect_p): Remove.
(ira_reg_equiv_len, ira_reg_equiv_invariant_p): Ditto.
(ira_reg_equiv_const): Ditto.
(ira_equiv_no_lvalue_p): New function.
* jump.c (true_regnum): Always use hard_regno for subreg_get_info
when lra is in progress.
* haifa-sched.c (sched_init): Pass new argument to
ira_setup_eliminable_regset.
* loop-invariant.c (calculate_loop_reg_pressure): Pass new
argument to ira_setup_eliminable_regset.
* lra.h: New.
* lra-int.h: Ditto.
* lra.c: Ditto.
* lra-assigns.c: Ditto.
* lra-constraints.c: Ditto.
* lra-coalesce.c: Ditto.
* lra-eliminations.c: Ditto.
* lra-lives.c: Ditto.
* lra-spills.c: Ditto.
* Makefile.in (LRA_INT_H): New.
(OBJS): Add lra.o, lra-assigns.o, lra-coalesce.o,
lra-constraints.o, lra-eliminations.o, lra-lives.o, and
lra-spills.o.
(dwarf2out.o): Add dependence on ira.h and lra.h.
(ira.o): Add dependence on lra.h.
(lra.o, lra-assigns.o, lra-coalesce.o, lra-constraints.o): New
entries.
(lra-eliminations.o, lra-lives.o, lra-spills.o): Ditto.
* output.h (alter_subreg): Add new argument.
* rtlanal.c (simplify_subreg_regno): Permit mode changes for LRA.
Permit ARG_POINTER_REGNUM and STACK_POINTER_REGNUM for LRA.
* recog.c (general_operand, register_operand): Accept paradoxical
FLOAT_MODE subregs for LRA.
(scratch_operand): Accept pseudos for LRA.
* rtl.h (lra_in_progress): New external.
(debug_bb_n_slim, debug_bb_slim, print_value_slim): New
prototypes.
(debug_rtl_slim, debug_insn_slim): Ditto.
* sdbout.c (sdbout_symbol): Pass new argument to alter_subreg.
* sched-vis.c (print_value_slim): New.
* target.def (lra_p): New hook.
(register_priority): Ditto.
(different_addr_displacement_p): Ditto.
(spill_class): Ditto.
* target-globals.h (this_target_lra_int): New external.
(target_globals): New member lra_int.
(restore_target_globals): Restore this_target_lra_int.
* target-globals.c: Include lra-int.h.
(default_target_globals): Add &default_target_lra_int.
* targhooks.c (default_lra_p): New function.
(default_register_priority): Ditto.
(default_different_addr_displacement_p): Ditto.
* targhooks.h (default_lra_p): Declare.
(default_register_priority): Ditto.
(default_different_addr_displacement_p): Ditto.
* timevar.def (TV_LRA, TV_LRA_ELIMINATE, TV_LRA_INHERITANCE): New.
(TV_LRA_CREATE_LIVE_RANGES, TV_LRA_ASSIGN, TV_LRA_COALESCE): New.
* config/arm/arm.c (load_multiple_sequence): Pass new argument toOB
alter_subreg.
(store_multiple_sequence): Ditto.
* config/i386/i386.h (enum ix86_tune_indices): Add
X86_TUNE_GENERAL_REGS_SSE_SPILL.
(TARGET_GENERAL_REGS_SSE_SPILL): New macro.
* config/i386/i386.c (initial_ix86_tune_features): Set up
X86_TUNE_GENERAL_REGS_SSE_SPILL for m_COREI7 and m_CORE2I7.
(ix86_lra_p, ix86_register_priority): New functions.
(ix86_secondary_reload): Add NON_Q_REGS, SIREG, DIREG.
(inline_secondary_memory_needed): Change assert.
(ix86_spill_class): New function.
(TARGET_LRA_P, TARGET_REGISTER_BANK, TARGET_SPILL_CLASS): New
macros.
* config/m68k/m68k.c (emit_move_sequence): Pass new argument to
alter_subreg.
* config/m32r/m32r.c (gen_split_move_double): Ditto.
* config/pa/pa.c (pa_emit_move_sequence): Ditto.
* config/sh/sh.md: Ditto.
* config/v850/v850.c (v850_reorg): Ditto.
* config/xtensa/xtensa.c (fixup_subreg_mem): Ditto.
* doc/md.texi: Add new interpretation of hint * for LRA.
* doc/passes.texi: Describe LRA pass.
* doc/tm.texi.in: Add TARGET_LRA_P, TARGET_REGISTER_PRIORITY,
TARGET_DIFFERENT_ADDR_DISPLACEMENT_P, and TARGET_SPILL_CLASS.
* doc/tm.texi: Update.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192719 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/lra-constraints.c')
-rw-r--r-- | gcc/lra-constraints.c | 5130 |
1 files changed, 5130 insertions, 0 deletions
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c new file mode 100644 index 00000000000..ec48e9ea02c --- /dev/null +++ b/gcc/lra-constraints.c @@ -0,0 +1,5130 @@ +/* Code for RTL transformations to satisfy insn constraints. + Copyright (C) 2010, 2011, 2012 + Free Software Foundation, Inc. + Contributed by Vladimir Makarov <vmakarov@redhat.com>. + + 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 code for 3 passes: constraint pass, + inheritance/split pass, and pass for undoing failed inheritance and + split. + + The major goal of constraint pass is to transform RTL to satisfy + insn and address constraints by: + o choosing insn alternatives; + o generating *reload insns* (or reloads in brief) and *reload + pseudos* which will get necessary hard registers later; + o substituting pseudos with equivalent values and removing the + instructions that initialized those pseudos. + + The constraint pass has biggest and most complicated code in LRA. + There are a lot of important details like: + o reuse of input reload pseudos to simplify reload pseudo + allocations; + o some heuristics to choose insn alternative to improve the + inheritance; + o early clobbers etc. + + The pass is mimicking former reload pass in alternative choosing + because the reload pass is oriented to current machine description + model. It might be changed if the machine description model is + changed. + + There is special code for preventing all LRA and this pass cycling + in case of bugs. + + On the first iteration of the pass we process every instruction and + choose an alternative for each one. On subsequent iterations we try + to avoid reprocessing instructions if we can be sure that the old + choice is still valid. + + The inheritance/spilt pass is to transform code to achieve + ineheritance and live range splitting. It is done on backward + traversal of EBBs. + + The inheritance optimization goal is to reuse values in hard + registers. There is analogous optimization in old reload pass. The + inheritance is achieved by following transformation: + + reload_p1 <- p reload_p1 <- p + ... new_p <- reload_p1 + ... => ... + reload_p2 <- p reload_p2 <- new_p + + where p is spilled and not changed between the insns. Reload_p1 is + also called *original pseudo* and new_p is called *inheritance + pseudo*. + + The subsequent assignment pass will try to assign the same (or + another if it is not possible) hard register to new_p as to + reload_p1 or reload_p2. + + If the assignment pass fails to assign a hard register to new_p, + this file will undo the inheritance and restore the original code. + This is because implementing the above sequence with a spilled + new_p would make the code much worse. The inheritance is done in + EBB scope. The above is just a simplified example to get an idea + of the inheritance as the inheritance is also done for non-reload + insns. + + Splitting (transformation) is also done in EBB scope on the same + pass as the inheritance: + + r <- ... or ... <- r r <- ... or ... <- r + ... s <- r (new insn -- save) + ... => + ... r <- s (new insn -- restore) + ... <- r ... <- r + + The *split pseudo* s is assigned to the hard register of the + original pseudo or hard register r. + + Splitting is done: + o In EBBs with high register pressure for global pseudos (living + in at least 2 BBs) and assigned to hard registers when there + are more one reloads needing the hard registers; + o for pseudos needing save/restore code around calls. + + If the split pseudo still has the same hard register as the + original pseudo after the subsequent assignment pass or the + original pseudo was split, the opposite transformation is done on + the same pass for undoing inheritance. */ + +#undef REG_OK_STRICT + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "hard-reg-set.h" +#include "rtl.h" +#include "tm_p.h" +#include "regs.h" +#include "insn-config.h" +#include "insn-codes.h" +#include "recog.h" +#include "output.h" +#include "addresses.h" +#include "target.h" +#include "function.h" +#include "expr.h" +#include "basic-block.h" +#include "except.h" +#include "optabs.h" +#include "df.h" +#include "ira.h" +#include "rtl-error.h" +#include "lra-int.h" + +/* Value of LRA_CURR_RELOAD_NUM at the beginning of BB of the current + insn. Remember that LRA_CURR_RELOAD_NUM is the number of emitted + reload insns. */ +static int bb_reload_num; + +/* The current insn being processed and corresponding its data (basic + block, the insn data, the insn static data, and the mode of each + operand). */ +static rtx curr_insn; +static basic_block curr_bb; +static lra_insn_recog_data_t curr_id; +static struct lra_static_insn_data *curr_static_id; +static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS]; + + + +/* Start numbers for new registers and insns at the current constraints + pass start. */ +static int new_regno_start; +static int new_insn_uid_start; + +/* Return hard regno of REGNO or if it is was not assigned to a hard + register, use a hard register from its allocno class. */ +static int +get_try_hard_regno (int regno) +{ + int hard_regno; + enum reg_class rclass; + + if ((hard_regno = regno) >= FIRST_PSEUDO_REGISTER) + hard_regno = lra_get_regno_hard_regno (regno); + if (hard_regno >= 0) + return hard_regno; + rclass = lra_get_allocno_class (regno); + if (rclass == NO_REGS) + return -1; + return ira_class_hard_regs[rclass][0]; +} + +/* Return final hard regno (plus offset) which will be after + elimination. We do this for matching constraints because the final + hard regno could have a different class. */ +static int +get_final_hard_regno (int hard_regno, int offset) +{ + if (hard_regno < 0) + return hard_regno; + hard_regno = lra_get_elimination_hard_regno (hard_regno); + return hard_regno + offset; +} + +/* Return hard regno of X after removing subreg and making + elimination. If X is not a register or subreg of register, return + -1. For pseudo use its assignment. */ +static int +get_hard_regno (rtx x) +{ + rtx reg; + int offset, hard_regno; + + reg = x; + if (GET_CODE (x) == SUBREG) + reg = SUBREG_REG (x); + if (! REG_P (reg)) + return -1; + if ((hard_regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER) + hard_regno = lra_get_regno_hard_regno (hard_regno); + if (hard_regno < 0) + return -1; + offset = 0; + if (GET_CODE (x) == SUBREG) + offset += subreg_regno_offset (hard_regno, GET_MODE (reg), + SUBREG_BYTE (x), GET_MODE (x)); + return get_final_hard_regno (hard_regno, offset); +} + +/* If REGNO is a hard register or has been allocated a hard register, + return the class of that register. If REGNO is a reload pseudo + created by the current constraints pass, return its allocno class. + Return NO_REGS otherwise. */ +static enum reg_class +get_reg_class (int regno) +{ + int hard_regno; + + if ((hard_regno = regno) >= FIRST_PSEUDO_REGISTER) + hard_regno = lra_get_regno_hard_regno (regno); + if (hard_regno >= 0) + { + hard_regno = get_final_hard_regno (hard_regno, 0); + return REGNO_REG_CLASS (hard_regno); + } + if (regno >= new_regno_start) + return lra_get_allocno_class (regno); + return NO_REGS; +} + +/* Return true if REG satisfies (or will satisfy) reg class constraint + CL. Use elimination first if REG is a hard register. If REG is a + reload pseudo created by this constraints pass, assume that it will + be allocated a hard register from its allocno class, but allow that + class to be narrowed to CL if it is currently a superset of CL. + + If NEW_CLASS is nonnull, set *NEW_CLASS to the new allocno class of + REGNO (reg), or NO_REGS if no change in its class was needed. */ +static bool +in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class) +{ + enum reg_class rclass, common_class; + enum machine_mode reg_mode; + int class_size, hard_regno, nregs, i, j; + int regno = REGNO (reg); + + if (new_class != NULL) + *new_class = NO_REGS; + if (regno < FIRST_PSEUDO_REGISTER) + { + rtx final_reg = reg; + rtx *final_loc = &final_reg; + + lra_eliminate_reg_if_possible (final_loc); + return TEST_HARD_REG_BIT (reg_class_contents[cl], REGNO (*final_loc)); + } + reg_mode = GET_MODE (reg); + rclass = get_reg_class (regno); + if (regno < new_regno_start + /* Do not allow the constraints for reload instructions to + influence the classes of new pseudos. These reloads are + typically moves that have many alternatives, and restricting + reload pseudos for one alternative may lead to situations + where other reload pseudos are no longer allocatable. */ + || INSN_UID (curr_insn) >= new_insn_uid_start) + /* When we don't know what class will be used finally for reload + pseudos, we use ALL_REGS. */ + return ((regno >= new_regno_start && rclass == ALL_REGS) + || (rclass != NO_REGS && ira_class_subset_p[rclass][cl] + && ! hard_reg_set_subset_p (reg_class_contents[cl], + lra_no_alloc_regs))); + else + { + common_class = ira_reg_class_subset[rclass][cl]; + if (new_class != NULL) + *new_class = common_class; + if (hard_reg_set_subset_p (reg_class_contents[common_class], + lra_no_alloc_regs)) + return false; + /* Check that there are enough allocatable regs. */ + class_size = ira_class_hard_regs_num[common_class]; + for (i = 0; i < class_size; i++) + { + hard_regno = ira_class_hard_regs[common_class][i]; + nregs = hard_regno_nregs[hard_regno][reg_mode]; + if (nregs == 1) + return true; + for (j = 0; j < nregs; j++) + if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j)) + break; + if (j >= nregs) + return true; + } + return false; + } +} + +/* Return true if REGNO satisfies a memory constraint. */ +static bool +in_mem_p (int regno) +{ + return get_reg_class (regno) == NO_REGS; +} + +/* If we have decided to substitute X with another value, return that + value, otherwise return X. */ +static rtx +get_equiv_substitution (rtx x) +{ + int regno; + rtx res; + + if (! REG_P (x) || (regno = REGNO (x)) < FIRST_PSEUDO_REGISTER + || ! ira_reg_equiv[regno].defined_p + || ! ira_reg_equiv[regno].profitable_p + || lra_get_regno_hard_regno (regno) >= 0) + return x; + if ((res = ira_reg_equiv[regno].memory) != NULL_RTX) + return res; + if ((res = ira_reg_equiv[regno].constant) != NULL_RTX) + return res; + if ((res = ira_reg_equiv[regno].invariant) != NULL_RTX) + return res; + gcc_unreachable (); +} + +/* Set up curr_operand_mode. */ +static void +init_curr_operand_mode (void) +{ + int nop = curr_static_id->n_operands; + for (int i = 0; i < nop; i++) + { + enum machine_mode mode = GET_MODE (*curr_id->operand_loc[i]); + if (mode == VOIDmode) + { + /* The .md mode for address operands is the mode of the + addressed value rather than the mode of the address itself. */ + if (curr_id->icode >= 0 && curr_static_id->operand[i].is_address) + mode = Pmode; + else + mode = curr_static_id->operand[i].mode; + } + curr_operand_mode[i] = mode; + } +} + + + +/* The page contains code to reuse input reloads. */ + +/* Structure describes input reload of the current insns. */ +struct input_reload +{ + /* Reloaded value. */ + rtx input; + /* Reload pseudo used. */ + rtx reg; +}; + +/* The number of elements in the following array. */ +static int curr_insn_input_reloads_num; +/* Array containing info about input reloads. It is used to find the + same input reload and reuse the reload pseudo in this case. */ +static struct input_reload curr_insn_input_reloads[LRA_MAX_INSN_RELOADS]; + +/* Initiate data concerning reuse of input reloads for the current + insn. */ +static void +init_curr_insn_input_reloads (void) +{ + curr_insn_input_reloads_num = 0; +} + +/* Change class of pseudo REGNO to NEW_CLASS. Print info about it + using TITLE. Output a new line if NL_P. */ +static void +change_class (int regno, enum reg_class new_class, + const char *title, bool nl_p) +{ + lra_assert (regno >= FIRST_PSEUDO_REGISTER); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "%s to class %s for r%d", + title, reg_class_names[new_class], regno); + setup_reg_classes (regno, new_class, NO_REGS, new_class); + if (lra_dump_file != NULL && nl_p) + fprintf (lra_dump_file, "\n"); +} + +/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse already + created input reload pseudo (only if TYPE is not OP_OUT). The + result pseudo is returned through RESULT_REG. Return TRUE if we + created a new pseudo, FALSE if we reused the already created input + reload pseudo. Use TITLE to describe new registers for debug + purposes. */ +static bool +get_reload_reg (enum op_type type, enum machine_mode mode, rtx original, + enum reg_class rclass, const char *title, rtx *result_reg) +{ + int i, regno; + enum reg_class new_class; + + if (type == OP_OUT) + { + *result_reg + = lra_create_new_reg_with_unique_value (mode, original, rclass, title); + return true; + } + for (i = 0; i < curr_insn_input_reloads_num; i++) + if (rtx_equal_p (curr_insn_input_reloads[i].input, original) + && in_class_p (curr_insn_input_reloads[i].reg, rclass, &new_class)) + { + lra_assert (! side_effects_p (original)); + *result_reg = curr_insn_input_reloads[i].reg; + regno = REGNO (*result_reg); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Reuse r%d for reload ", regno); + print_value_slim (lra_dump_file, original, 1); + } + if (rclass != new_class) + change_class (regno, new_class, ", change", false); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n"); + return false; + } + *result_reg = lra_create_new_reg (mode, original, rclass, title); + lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS); + curr_insn_input_reloads[curr_insn_input_reloads_num].input = original; + curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = *result_reg; + return true; +} + + + +/* The page contains code to extract memory address parts. */ + +/* Info about base and index regs of an address. In some rare cases, + base/index register can be actually memory. In this case we will + reload it. */ +struct address +{ + /* NULL if there is no a base register. */ + rtx *base_reg_loc; + /* Second location of {post/pre}_modify, NULL otherwise. */ + rtx *base_reg_loc2; + /* NULL if there is no an index register. */ + rtx *index_reg_loc; + /* Location of index reg * scale or index_reg_loc otherwise. */ + rtx *index_loc; + /* NULL if there is no a displacement. */ + rtx *disp_loc; + /* Defined if base_reg_loc is not NULL. */ + enum rtx_code base_outer_code, index_code; + /* True if the base register is modified in the address, for + example, in PRE_INC. */ + bool base_modify_p; +}; + +/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudos. */ +static inline bool +ok_for_index_p_nonstrict (rtx reg) +{ + unsigned regno = REGNO (reg); + + return regno >= FIRST_PSEUDO_REGISTER || REGNO_OK_FOR_INDEX_P (regno); +} + +/* A version of regno_ok_for_base_p for use here, when all pseudos + should count as OK. Arguments as for regno_ok_for_base_p. */ +static inline bool +ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as, + enum rtx_code outer_code, enum rtx_code index_code) +{ + unsigned regno = REGNO (reg); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + return ok_for_base_p_1 (regno, mode, as, outer_code, index_code); +} + +/* Process address part in space AS (or all address if TOP_P) with + location *LOC to extract address characteristics. + + If CONTEXT_P is false, we are looking at the base part of an + address, otherwise we are looking at the index part. + + MODE is the mode of the memory reference; OUTER_CODE and INDEX_CODE + give the context that the rtx appears in; MODIFY_P if *LOC is + modified. */ +static void +extract_loc_address_regs (bool top_p, enum machine_mode mode, addr_space_t as, + rtx *loc, bool context_p, enum rtx_code outer_code, + enum rtx_code index_code, + bool modify_p, struct address *ad) +{ + rtx x = *loc; + enum rtx_code code = GET_CODE (x); + bool base_ok_p; + + switch (code) + { + case CONST_INT: + case CONST: + case SYMBOL_REF: + case LABEL_REF: + if (! context_p) + { + lra_assert (top_p); + ad->disp_loc = loc; + } + return; + + case CC0: + case PC: + return; + + case PLUS: + case LO_SUM: + /* When we have an address that is a sum, we must determine + whether registers are "base" or "index" regs. If there is a + sum of two registers, we must choose one to be the + "base". */ + { + rtx *arg0_loc = &XEXP (x, 0); + rtx *arg1_loc = &XEXP (x, 1); + rtx *tloc; + rtx arg0 = *arg0_loc; + rtx arg1 = *arg1_loc; + enum rtx_code code0 = GET_CODE (arg0); + enum rtx_code code1 = GET_CODE (arg1); + + /* Look inside subregs. */ + if (code0 == SUBREG) + { + arg0_loc = &SUBREG_REG (arg0); + arg0 = *arg0_loc; + code0 = GET_CODE (arg0); + } + if (code1 == SUBREG) + { + arg1_loc = &SUBREG_REG (arg1); + arg1 = *arg1_loc; + code1 = GET_CODE (arg1); + } + + if (CONSTANT_P (arg0) + || code1 == PLUS || code1 == MULT || code1 == ASHIFT) + { + tloc = arg1_loc; + arg1_loc = arg0_loc; + arg0_loc = tloc; + arg0 = *arg0_loc; + code0 = GET_CODE (arg0); + arg1 = *arg1_loc; + code1 = GET_CODE (arg1); + } + /* If this machine only allows one register per address, it + must be in the first operand. */ + if (MAX_REGS_PER_ADDRESS == 1 || code == LO_SUM) + { + lra_assert (ad->disp_loc == NULL); + ad->disp_loc = arg1_loc; + extract_loc_address_regs (false, mode, as, arg0_loc, false, code, + code1, modify_p, ad); + } + /* Base + disp addressing */ + else if (code0 != PLUS && code0 != MULT && code0 != ASHIFT + && CONSTANT_P (arg1)) + { + lra_assert (ad->disp_loc == NULL); + ad->disp_loc = arg1_loc; + extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS, + code1, modify_p, ad); + } + /* If index and base registers are the same on this machine, + just record registers in any non-constant operands. We + assume here, as well as in the tests below, that all + addresses are in canonical form. */ + else if (INDEX_REG_CLASS + == base_reg_class (VOIDmode, as, PLUS, SCRATCH) + && code0 != PLUS && code0 != MULT && code0 != ASHIFT) + { + extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS, + code1, modify_p, ad); + lra_assert (! CONSTANT_P (arg1)); + extract_loc_address_regs (false, mode, as, arg1_loc, true, PLUS, + code0, modify_p, ad); + } + /* It might be [base + ]index * scale + disp. */ + else if (CONSTANT_P (arg1)) + { + lra_assert (ad->disp_loc == NULL); + ad->disp_loc = arg1_loc; + extract_loc_address_regs (false, mode, as, arg0_loc, context_p, + PLUS, code0, modify_p, ad); + } + /* If both operands are registers but one is already a hard + register of index or reg-base class, give the other the + class that the hard register is not. */ + else if (code0 == REG && code1 == REG + && REGNO (arg0) < FIRST_PSEUDO_REGISTER + && ((base_ok_p + = ok_for_base_p_nonstrict (arg0, mode, as, PLUS, REG)) + || ok_for_index_p_nonstrict (arg0))) + { + extract_loc_address_regs (false, mode, as, arg0_loc, ! base_ok_p, + PLUS, REG, modify_p, ad); + extract_loc_address_regs (false, mode, as, arg1_loc, base_ok_p, + PLUS, REG, modify_p, ad); + } + else if (code0 == REG && code1 == REG + && REGNO (arg1) < FIRST_PSEUDO_REGISTER + && ((base_ok_p + = ok_for_base_p_nonstrict (arg1, mode, as, PLUS, REG)) + || ok_for_index_p_nonstrict (arg1))) + { + extract_loc_address_regs (false, mode, as, arg0_loc, base_ok_p, + PLUS, REG, modify_p, ad); + extract_loc_address_regs (false, mode, as, arg1_loc, ! base_ok_p, + PLUS, REG, modify_p, ad); + } + /* Otherwise, count equal chances that each might be a base or + index register. This case should be rare. */ + else + { + extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS, + code1, modify_p, ad); + extract_loc_address_regs (false, mode, as, arg1_loc, + ad->base_reg_loc != NULL, PLUS, + code0, modify_p, ad); + } + } + break; + + case MULT: + case ASHIFT: + { + rtx *arg0_loc = &XEXP (x, 0); + enum rtx_code code0 = GET_CODE (*arg0_loc); + + if (code0 == CONST_INT) + arg0_loc = &XEXP (x, 1); + extract_loc_address_regs (false, mode, as, arg0_loc, true, + outer_code, code, modify_p, ad); + lra_assert (ad->index_loc == NULL); + ad->index_loc = loc; + break; + } + + case POST_MODIFY: + case PRE_MODIFY: + extract_loc_address_regs (false, mode, as, &XEXP (x, 0), false, + code, GET_CODE (XEXP (XEXP (x, 1), 1)), + true, ad); + lra_assert (rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0))); + ad->base_reg_loc2 = &XEXP (XEXP (x, 1), 0); + if (REG_P (XEXP (XEXP (x, 1), 1))) + extract_loc_address_regs (false, mode, as, &XEXP (XEXP (x, 1), 1), + true, code, REG, modify_p, ad); + break; + + case POST_INC: + case PRE_INC: + case POST_DEC: + case PRE_DEC: + extract_loc_address_regs (false, mode, as, &XEXP (x, 0), false, code, + SCRATCH, true, ad); + break; + + /* We process memory as a register. That means we flatten + addresses. In other words, the final code will never + contains memory in an address even if the target supports + such addresses (it is too rare these days). Memory also can + occur in address as a result some previous transformations + like equivalence substitution. */ + case MEM: + case REG: + if (context_p) + { + lra_assert (ad->index_reg_loc == NULL); + ad->index_reg_loc = loc; + } + else + { + lra_assert (ad->base_reg_loc == NULL); + ad->base_reg_loc = loc; + ad->base_outer_code = outer_code; + ad->index_code = index_code; + ad->base_modify_p = modify_p; + } + break; + default: + { + const char *fmt = GET_RTX_FORMAT (code); + int i; + + if (GET_RTX_LENGTH (code) != 1 + || fmt[0] != 'e' || GET_CODE (XEXP (x, 0)) != UNSPEC) + { + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + extract_loc_address_regs (false, mode, as, &XEXP (x, i), + context_p, code, SCRATCH, + modify_p, ad); + break; + } + /* fall through for case UNARY_OP (UNSPEC ...) */ + } + + case UNSPEC: + if (ad->disp_loc == NULL) + ad->disp_loc = loc; + else if (ad->base_reg_loc == NULL) + { + ad->base_reg_loc = loc; + ad->base_outer_code = outer_code; + ad->index_code = index_code; + ad->base_modify_p = modify_p; + } + else + { + lra_assert (ad->index_reg_loc == NULL); + ad->index_reg_loc = loc; + } + break; + + } +} + + +/* Describe address *LOC in AD. There are two cases: + - *LOC is the address in a (mem ...). In this case OUTER_CODE is MEM + and AS is the mem's address space. + - *LOC is matched to an address constraint such as 'p'. In this case + OUTER_CODE is ADDRESS and AS is ADDR_SPACE_GENERIC. */ +static void +extract_address_regs (enum machine_mode mem_mode, addr_space_t as, + rtx *loc, enum rtx_code outer_code, struct address *ad) +{ + ad->base_reg_loc = ad->base_reg_loc2 + = ad->index_reg_loc = ad->index_loc = ad->disp_loc = NULL; + ad->base_outer_code = SCRATCH; + ad->index_code = SCRATCH; + ad->base_modify_p = false; + extract_loc_address_regs (true, mem_mode, as, loc, false, outer_code, + SCRATCH, false, ad); + if (ad->index_loc == NULL) + /* SUBREG ??? */ + ad->index_loc = ad->index_reg_loc; +} + + + +/* The page contains major code to choose the current insn alternative + and generate reloads for it. */ + +/* Return the offset from REGNO of the least significant register + in (reg:MODE REGNO). + + This function is used to tell whether two registers satisfy + a matching constraint. (reg:MODE1 REGNO1) matches (reg:MODE2 REGNO2) if: + + REGNO1 + lra_constraint_offset (REGNO1, MODE1) + == REGNO2 + lra_constraint_offset (REGNO2, MODE2) */ +int +lra_constraint_offset (int regno, enum machine_mode mode) +{ + lra_assert (regno < FIRST_PSEUDO_REGISTER); + if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (mode) > UNITS_PER_WORD + && SCALAR_INT_MODE_P (mode)) + return hard_regno_nregs[regno][mode] - 1; + return 0; +} + +/* 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 + auto-increment and auto-decrement. This is specifically intended for + process_alt_operands to use in determining whether two operands + match. X is the operand whose number is the lower of the two. + + It is supposed that X is the output operand and Y is the input + operand. Y_HARD_REGNO is the final hard regno of register Y or + register in subreg Y as we know it now. Otherwise, it is a + negative value. */ +static bool +operands_match_p (rtx x, rtx y, int y_hard_regno) +{ + int i; + RTX_CODE code = GET_CODE (x); + const char *fmt; + + if (x == y) + return true; + if ((code == REG || (code == SUBREG && REG_P (SUBREG_REG (x)))) + && (REG_P (y) || (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))))) + { + int j; + + i = get_hard_regno (x); + if (i < 0) + goto slow; + + if ((j = y_hard_regno) < 0) + goto slow; + + i += lra_constraint_offset (i, GET_MODE (x)); + j += lra_constraint_offset (j, GET_MODE (y)); + + return i == j; + } + + /* If two operands must match, because they are really a single + operand of an assembler insn, then two post-increments are invalid + because the assembler insn would increment only once. On the + other hand, a post-increment matches ordinary indexing if the + post-increment is the output operand. */ + if (code == POST_DEC || code == POST_INC || code == POST_MODIFY) + return operands_match_p (XEXP (x, 0), y, y_hard_regno); + + /* Two pre-increments are invalid because the assembler insn would + increment only once. On the other hand, a pre-increment matches + ordinary indexing if the pre-increment is the input operand. */ + if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC + || GET_CODE (y) == PRE_MODIFY) + return operands_match_p (x, XEXP (y, 0), -1); + + slow: + + if (code == REG && GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)) + && x == SUBREG_REG (y)) + return true; + if (GET_CODE (y) == REG && code == SUBREG && REG_P (SUBREG_REG (x)) + && SUBREG_REG (x) == y) + return true; + + /* Now we have disposed of all the cases in which different rtx + codes can match. */ + if (code != GET_CODE (y)) + return false; + + /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ + if (GET_MODE (x) != GET_MODE (y)) + return false; + + switch (code) + { + CASE_CONST_UNIQUE: + return false; + + case LABEL_REF: + return XEXP (x, 0) == XEXP (y, 0); + 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 false for the whole things. */ + + 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 false; + break; + + case 'i': + if (XINT (x, i) != XINT (y, i)) + return false; + break; + + case 'e': + val = operands_match_p (XEXP (x, i), XEXP (y, i), -1); + if (val == 0) + return false; + break; + + case '0': + break; + + case 'E': + if (XVECLEN (x, i) != XVECLEN (y, i)) + return false; + for (j = XVECLEN (x, i) - 1; j >= 0; --j) + { + val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j), -1); + if (val == 0) + return false; + } + 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 true; +} + +/* 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. */ +#define SMALL_REGISTER_CLASS_P(C) \ + (reg_class_size [(C)] == 1 \ + || (reg_class_size [(C)] >= 1 && targetm.class_likely_spilled_p (C))) + +/* If REG is a reload pseudo, try to make its class satisfying CL. */ +static void +narrow_reload_pseudo_class (rtx reg, enum reg_class cl) +{ + enum reg_class rclass; + + /* Do not make more accurate class from reloads generated. They are + mostly moves with a lot of constraints. Making more accurate + class may results in very narrow class and impossibility of find + registers for several reloads of one insn. */ + if (INSN_UID (curr_insn) >= new_insn_uid_start) + return; + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (! REG_P (reg) || (int) REGNO (reg) < new_regno_start) + return; + if (in_class_p (reg, cl, &rclass) && rclass != cl) + change_class (REGNO (reg), rclass, " Change", true); +} + +/* Generate reloads for matching OUT and INS (array of input operand + numbers with end marker -1) with reg class GOAL_CLASS. Add input + and output reloads correspondingly to the lists *BEFORE and + *AFTER. */ +static void +match_reload (signed char out, signed char *ins, enum reg_class goal_class, + rtx *before, rtx *after) +{ + int i, in; + rtx new_in_reg, new_out_reg, reg; + enum machine_mode inmode, outmode; + rtx in_rtx = *curr_id->operand_loc[ins[0]]; + rtx out_rtx = *curr_id->operand_loc[out]; + + outmode = curr_operand_mode[out]; + inmode = curr_operand_mode[ins[0]]; + push_to_sequence (*before); + if (inmode != outmode) + { + if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode)) + { + reg = new_in_reg + = lra_create_new_reg_with_unique_value (inmode, in_rtx, + goal_class, ""); + if (SCALAR_INT_MODE_P (inmode)) + new_out_reg = gen_lowpart_SUBREG (outmode, reg); + else + new_out_reg = gen_rtx_SUBREG (outmode, reg, 0); + } + else + { + reg = new_out_reg + = lra_create_new_reg_with_unique_value (outmode, out_rtx, + goal_class, ""); + if (SCALAR_INT_MODE_P (outmode)) + new_in_reg = gen_lowpart_SUBREG (inmode, reg); + else + new_in_reg = gen_rtx_SUBREG (inmode, reg, 0); + /* NEW_IN_REG is non-paradoxical subreg. We don't want + NEW_OUT_REG living above. We add clobber clause for + this. */ + emit_clobber (new_out_reg); + } + } + else + { + /* Pseudos have values -- see comments for lra_reg_info. + Different pseudos with the same value do not conflict even if + they live in the same place. When we create a pseudo we + assign value of original pseudo (if any) from which we + created the new pseudo. If we create the pseudo from the + input pseudo, the new pseudo will no conflict with the input + pseudo which is wrong when the input pseudo lives after the + insn and as the new pseudo value is changed by the insn + output. Therefore we create the new pseudo from the output. + + We cannot reuse the current output register because we might + have a situation like "a <- a op b", where the constraints + force the second input operand ("b") to match the output + operand ("a"). "b" must then be copied into a new register + so that it doesn't clobber the current value of "a". */ + + new_in_reg = new_out_reg + = lra_create_new_reg_with_unique_value (outmode, out_rtx, + goal_class, ""); + } + /* In and out operand can be got from transformations before + processing insn constraints. One example of such transformations + is subreg reloading (see function simplify_operand_subreg). The + new pseudos created by the transformations might have inaccurate + class (ALL_REGS) and we should make their classes more + accurate. */ + narrow_reload_pseudo_class (in_rtx, goal_class); + narrow_reload_pseudo_class (out_rtx, goal_class); + lra_emit_move (copy_rtx (new_in_reg), in_rtx); + *before = get_insns (); + end_sequence (); + for (i = 0; (in = ins[i]) >= 0; i++) + { + lra_assert + (GET_MODE (*curr_id->operand_loc[in]) == VOIDmode + || GET_MODE (new_in_reg) == GET_MODE (*curr_id->operand_loc[in])); + *curr_id->operand_loc[in] = new_in_reg; + } + lra_update_dups (curr_id, ins); + if (find_reg_note (curr_insn, REG_UNUSED, out_rtx) == NULL_RTX) + { + start_sequence (); + lra_emit_move (out_rtx, copy_rtx (new_out_reg)); + emit_insn (*after); + *after = get_insns (); + end_sequence (); + } + *curr_id->operand_loc[out] = new_out_reg; + lra_update_dup (curr_id, out); +} + +/* Return register class which is union of all reg classes in insn + constraint alternative string starting with P. */ +static enum reg_class +reg_class_from_constraints (const char *p) +{ + int c, len; + enum reg_class op_class = NO_REGS; + + do + switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) + { + case '#': + case ',': + return op_class; + + case 'p': + op_class = (reg_class_subunion + [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH)]); + break; + + case 'g': + case 'r': + op_class = reg_class_subunion[op_class][GENERAL_REGS]; + break; + + default: + if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) + { +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + op_class + = (reg_class_subunion + [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH)]); +#endif + break; + } + + op_class + = reg_class_subunion[op_class][REG_CLASS_FROM_CONSTRAINT (c, p)]; + break; + } + while ((p += len), c); + return op_class; +} + +/* If OP is a register, return the class of the register as per + get_reg_class, otherwise return NO_REGS. */ +static inline enum reg_class +get_op_class (rtx op) +{ + return REG_P (op) ? get_reg_class (REGNO (op)) : NO_REGS; +} + +/* Return generated insn mem_pseudo:=val if TO_P or val:=mem_pseudo + otherwise. If modes of MEM_PSEUDO and VAL are different, use + SUBREG for VAL to make them equal. */ +static rtx +emit_spill_move (bool to_p, rtx mem_pseudo, rtx val) +{ + if (GET_MODE (mem_pseudo) != GET_MODE (val)) + val = gen_rtx_SUBREG (GET_MODE (mem_pseudo), + GET_CODE (val) == SUBREG ? SUBREG_REG (val) : val, + 0); + return (to_p + ? gen_move_insn (mem_pseudo, val) + : gen_move_insn (val, mem_pseudo)); +} + +/* Process a special case insn (register move), return true if we + don't need to process it anymore. Return that RTL was changed + through CHANGE_P and macro SECONDARY_MEMORY_NEEDED says to use + secondary memory through SEC_MEM_P. */ +static bool +check_and_process_move (bool *change_p, bool *sec_mem_p) +{ + int sregno, dregno; + rtx set, dest, src, dreg, sreg, old_sreg, new_reg, before, scratch_reg; + enum reg_class dclass, sclass, secondary_class; + enum machine_mode sreg_mode; + secondary_reload_info sri; + + *sec_mem_p = *change_p = false; + if ((set = single_set (curr_insn)) == NULL) + return false; + dreg = dest = SET_DEST (set); + sreg = src = SET_SRC (set); + /* Quick check on the right move insn which does not need + reloads. */ + if ((dclass = get_op_class (dest)) != NO_REGS + && (sclass = get_op_class (src)) != NO_REGS + /* The backend guarantees that register moves of cost 2 never + need reloads. */ + && targetm.register_move_cost (GET_MODE (src), dclass, sclass) == 2) + return true; + if (GET_CODE (dest) == SUBREG) + dreg = SUBREG_REG (dest); + if (GET_CODE (src) == SUBREG) + sreg = SUBREG_REG (src); + if (! REG_P (dreg) || ! REG_P (sreg)) + return false; + sclass = dclass = NO_REGS; + dreg = get_equiv_substitution (dreg); + if (REG_P (dreg)) + dclass = get_reg_class (REGNO (dreg)); + if (dclass == ALL_REGS) + /* ALL_REGS is used for new pseudos created by transformations + like reload of SUBREG_REG (see function + simplify_operand_subreg). We don't know their class yet. We + should figure out the class from processing the insn + constraints not in this fast path function. Even if ALL_REGS + were a right class for the pseudo, secondary_... hooks usually + are not define for ALL_REGS. */ + return false; + sreg_mode = GET_MODE (sreg); + old_sreg = sreg; + sreg = get_equiv_substitution (sreg); + if (REG_P (sreg)) + sclass = get_reg_class (REGNO (sreg)); + if (sclass == ALL_REGS) + /* See comments above. */ + return false; +#ifdef SECONDARY_MEMORY_NEEDED + if (dclass != NO_REGS && sclass != NO_REGS + && SECONDARY_MEMORY_NEEDED (sclass, dclass, GET_MODE (src))) + { + *sec_mem_p = true; + return false; + } +#endif + sri.prev_sri = NULL; + sri.icode = CODE_FOR_nothing; + sri.extra_cost = 0; + secondary_class = NO_REGS; + /* Set up hard register for a reload pseudo for hook + secondary_reload because some targets just ignore unassigned + pseudos in the hook. */ + if (dclass != NO_REGS && lra_get_regno_hard_regno (REGNO (dreg)) < 0) + { + dregno = REGNO (dreg); + reg_renumber[dregno] = ira_class_hard_regs[dclass][0]; + } + else + dregno = -1; + if (sclass != NO_REGS && lra_get_regno_hard_regno (REGNO (sreg)) < 0) + { + sregno = REGNO (sreg); + reg_renumber[sregno] = ira_class_hard_regs[sclass][0]; + } + else + sregno = -1; + if (sclass != NO_REGS) + secondary_class + = (enum reg_class) targetm.secondary_reload (false, dest, + (reg_class_t) sclass, + GET_MODE (src), &sri); + if (sclass == NO_REGS + || ((secondary_class != NO_REGS || sri.icode != CODE_FOR_nothing) + && dclass != NO_REGS)) + { +#if ENABLE_ASSERT_CHECKING + enum reg_class old_sclass = secondary_class; + secondary_reload_info old_sri = sri; +#endif + + sri.prev_sri = NULL; + sri.icode = CODE_FOR_nothing; + sri.extra_cost = 0; + secondary_class + = (enum reg_class) targetm.secondary_reload (true, sreg, + (reg_class_t) dclass, + sreg_mode, &sri); + /* Check the target hook consistency. */ + lra_assert + ((secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing) + || (old_sclass == NO_REGS && old_sri.icode == CODE_FOR_nothing) + || (secondary_class == old_sclass && sri.icode == old_sri.icode)); + } + if (sregno >= 0) + reg_renumber [sregno] = -1; + if (dregno >= 0) + reg_renumber [dregno] = -1; + if (secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing) + return false; + *change_p = true; + new_reg = NULL_RTX; + if (secondary_class != NO_REGS) + new_reg = lra_create_new_reg_with_unique_value (sreg_mode, NULL_RTX, + secondary_class, + "secondary"); + start_sequence (); + if (old_sreg != sreg) + sreg = copy_rtx (sreg); + if (sri.icode == CODE_FOR_nothing) + lra_emit_move (new_reg, sreg); + else + { + enum reg_class scratch_class; + + scratch_class = (reg_class_from_constraints + (insn_data[sri.icode].operand[2].constraint)); + scratch_reg = (lra_create_new_reg_with_unique_value + (insn_data[sri.icode].operand[2].mode, NULL_RTX, + scratch_class, "scratch")); + emit_insn (GEN_FCN (sri.icode) (new_reg != NULL_RTX ? new_reg : dest, + sreg, scratch_reg)); + } + before = get_insns (); + end_sequence (); + lra_process_new_insns (curr_insn, before, NULL_RTX, "Inserting the move"); + if (new_reg != NULL_RTX) + { + if (GET_CODE (src) == SUBREG) + SUBREG_REG (src) = new_reg; + else + SET_SRC (set) = new_reg; + } + else + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, "Deleting move %u\n", INSN_UID (curr_insn)); + debug_rtl_slim (lra_dump_file, curr_insn, curr_insn, -1, 0); + } + lra_set_insn_deleted (curr_insn); + return true; + } + return false; +} + +/* The following data describe the result of process_alt_operands. + The data are used in curr_insn_transform to generate reloads. */ + +/* The chosen reg classes which should be used for the corresponding + operands. */ +static enum reg_class goal_alt[MAX_RECOG_OPERANDS]; +/* True if the operand should be the same as another operand and that + other operand does not need a reload. */ +static bool goal_alt_match_win[MAX_RECOG_OPERANDS]; +/* True if the operand does not need a reload. */ +static bool goal_alt_win[MAX_RECOG_OPERANDS]; +/* True if the operand can be offsetable memory. */ +static bool goal_alt_offmemok[MAX_RECOG_OPERANDS]; +/* The number of an operand to which given operand can be matched to. */ +static int goal_alt_matches[MAX_RECOG_OPERANDS]; +/* The number of elements in the following array. */ +static int goal_alt_dont_inherit_ops_num; +/* Numbers of operands whose reload pseudos should not be inherited. */ +static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; +/* True if the insn commutative operands should be swapped. */ +static bool goal_alt_swapped; +/* The chosen insn alternative. */ +static int goal_alt_number; + +/* The following five variables are used to choose the best insn + alternative. They reflect final characteristics of the best + alternative. */ + +/* Number of necessary reloads and overall cost reflecting the + previous value and other unpleasantness of the best alternative. */ +static int best_losers, best_overall; +/* Number of small register classes used for operands of the best + alternative. */ +static int best_small_class_operands_num; +/* Overall number hard registers used for reloads. For example, on + some targets we need 2 general registers to reload DFmode and only + one floating point register. */ +static int best_reload_nregs; +/* Overall number reflecting distances of previous reloading the same + value. The distances are counted from the current BB start. It is + used to improve inheritance chances. */ +static int best_reload_sum; + +/* True if the current insn should have no correspondingly input or + output reloads. */ +static bool no_input_reloads_p, no_output_reloads_p; + +/* True if we swapped the commutative operands in the current + insn. */ +static int curr_swapped; + +/* Arrange for address element *LOC to be a register of class CL. + Add any input reloads to list BEFORE. AFTER is nonnull if *LOC is an + automodified value; handle that case by adding the required output + reloads to list AFTER. Return true if the RTL was changed. */ +static bool +process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl) +{ + int regno; + enum reg_class rclass, new_class; + rtx reg = *loc; + rtx new_reg; + enum machine_mode mode; + bool before_p = false; + + mode = GET_MODE (reg); + if (! REG_P (reg)) + { + /* Always reload memory in an address even if the target supports + such addresses. */ + new_reg = lra_create_new_reg_with_unique_value (mode, reg, cl, "address"); + before_p = true; + } + else + { + regno = REGNO (reg); + rclass = get_reg_class (regno); + if ((*loc = get_equiv_substitution (reg)) != reg) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + "Changing pseudo %d in address of insn %u on equiv ", + REGNO (reg), INSN_UID (curr_insn)); + print_value_slim (lra_dump_file, *loc, 1); + fprintf (lra_dump_file, "\n"); + } + *loc = copy_rtx (*loc); + } + if (*loc != reg || ! in_class_p (reg, cl, &new_class)) + { + reg = *loc; + if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT, + mode, reg, cl, "address", &new_reg)) + before_p = true; + } + else if (new_class != NO_REGS && rclass != new_class) + { + change_class (regno, new_class, " Change", true); + return false; + } + else + return false; + } + if (before_p) + { + push_to_sequence (*before); + lra_emit_move (new_reg, reg); + *before = get_insns (); + end_sequence (); + } + *loc = new_reg; + if (after != NULL) + { + start_sequence (); + lra_emit_move (reg, new_reg); + emit_insn (*after); + *after = get_insns (); + end_sequence (); + } + return true; +} + +#ifndef SLOW_UNALIGNED_ACCESS +#define SLOW_UNALIGNED_ACCESS(mode, align) 0 +#endif + +/* Make reloads for subreg in operand NOP with internal subreg mode + REG_MODE, add new reloads for further processing. Return true if + any reload was generated. */ +static bool +simplify_operand_subreg (int nop, enum machine_mode reg_mode) +{ + int hard_regno; + rtx before, after; + enum machine_mode mode; + rtx reg, new_reg; + rtx operand = *curr_id->operand_loc[nop]; + + before = after = NULL_RTX; + + if (GET_CODE (operand) != SUBREG) + return false; + + mode = GET_MODE (operand); + reg = SUBREG_REG (operand); + /* If we change address for paradoxical subreg of memory, the + address might violate the necessary alignment or the access might + be slow. So take this into consideration. */ + if ((MEM_P (reg) + && ((! STRICT_ALIGNMENT + && ! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (reg))) + || MEM_ALIGN (reg) >= GET_MODE_ALIGNMENT (mode))) + || (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)) + { + alter_subreg (curr_id->operand_loc[nop], false); + return true; + } + /* Put constant into memory when we have mixed modes. It generates + a better code in most cases as it does not need a secondary + reload memory. It also prevents LRA looping when LRA is using + secondary reload memory again and again. */ + if (CONSTANT_P (reg) && CONST_POOL_OK_P (reg_mode, reg) + && SCALAR_INT_MODE_P (reg_mode) != SCALAR_INT_MODE_P (mode)) + { + SUBREG_REG (operand) = force_const_mem (reg_mode, reg); + alter_subreg (curr_id->operand_loc[nop], false); + return true; + } + /* Force a reload of the SUBREG_REG if this is a constant or PLUS or + if there may be a problem accessing OPERAND in the outer + mode. */ + if ((REG_P (reg) + && REGNO (reg) >= FIRST_PSEUDO_REGISTER + && (hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0 + /* Don't reload paradoxical subregs because we could be looping + having repeatedly final regno out of hard regs range. */ + && (hard_regno_nregs[hard_regno][GET_MODE (reg)] + >= hard_regno_nregs[hard_regno][mode]) + && simplify_subreg_regno (hard_regno, GET_MODE (reg), + SUBREG_BYTE (operand), mode) < 0) + || CONSTANT_P (reg) || GET_CODE (reg) == PLUS || MEM_P (reg)) + { + enum op_type type = curr_static_id->operand[nop].type; + /* The class will be defined later in curr_insn_transform. */ + enum reg_class rclass + = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); + + new_reg = lra_create_new_reg_with_unique_value (reg_mode, reg, rclass, + "subreg reg"); + bitmap_set_bit (&lra_optional_reload_pseudos, REGNO (new_reg)); + if (type != OP_OUT + || GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode)) + { + push_to_sequence (before); + lra_emit_move (new_reg, reg); + before = get_insns (); + end_sequence (); + } + if (type != OP_IN) + { + start_sequence (); + lra_emit_move (reg, new_reg); + emit_insn (after); + after = get_insns (); + end_sequence (); + } + SUBREG_REG (operand) = new_reg; + lra_process_new_insns (curr_insn, before, after, + "Inserting subreg reload"); + return true; + } + return false; +} + +/* Return TRUE if X refers for a hard register from SET. */ +static bool +uses_hard_regs_p (rtx x, HARD_REG_SET set) +{ + int i, j, x_hard_regno; + enum machine_mode mode; + const char *fmt; + enum rtx_code code; + + if (x == NULL_RTX) + return false; + code = GET_CODE (x); + mode = GET_MODE (x); + if (code == SUBREG) + { + x = SUBREG_REG (x); + code = GET_CODE (x); + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode)) + mode = GET_MODE (x); + } + + if (REG_P (x)) + { + x_hard_regno = get_hard_regno (x); + return (x_hard_regno >= 0 + && overlaps_hard_reg_set_p (set, mode, x_hard_regno)); + } + if (MEM_P (x)) + { + struct address ad; + enum machine_mode mode = GET_MODE (x); + rtx *addr_loc = &XEXP (x, 0); + + extract_address_regs (mode, MEM_ADDR_SPACE (x), addr_loc, MEM, &ad); + if (ad.base_reg_loc != NULL) + { + if (uses_hard_regs_p (*ad.base_reg_loc, set)) + return true; + } + if (ad.index_reg_loc != NULL) + { + if (uses_hard_regs_p (*ad.index_reg_loc, set)) + return true; + } + } + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (uses_hard_regs_p (XEXP (x, i), set)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (uses_hard_regs_p (XVECEXP (x, i, j), set)) + return true; + } + } + return false; +} + +/* Return true if OP is a spilled pseudo. */ +static inline bool +spilled_pseudo_p (rtx op) +{ + return (REG_P (op) + && REGNO (op) >= FIRST_PSEUDO_REGISTER && in_mem_p (REGNO (op))); +} + +/* Return true if X is a general constant. */ +static inline bool +general_constant_p (rtx x) +{ + return CONSTANT_P (x) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (x)); +} + +/* Cost factor for each additional reload and maximal cost bound for + insn reloads. One might ask about such strange numbers. Their + values occurred historically from former reload pass. */ +#define LOSER_COST_FACTOR 6 +#define MAX_OVERALL_COST_BOUND 600 + +/* Major function to choose the current insn alternative and what + operands should be reloaded and how. If ONLY_ALTERNATIVE is not + negative we should consider only this alternative. Return false if + we can not choose the alternative or find how to reload the + operands. */ +static bool +process_alt_operands (int only_alternative) +{ + bool ok_p = false; + int nop, small_class_operands_num, overall, nalt; + int n_alternatives = curr_static_id->n_alternatives; + int n_operands = curr_static_id->n_operands; + /* LOSERS counts the operands that don't fit this alternative and + would require loading. */ + int losers; + /* REJECT is a count of how undesirable this alternative says it is + if any reloading is required. If the alternative matches exactly + then REJECT is ignored, but otherwise it gets this much counted + against it in addition to the reloading needed. */ + int reject; + /* The number of elements in the following array. */ + int early_clobbered_regs_num; + /* Numbers of operands which are early clobber registers. */ + int early_clobbered_nops[MAX_RECOG_OPERANDS]; + enum reg_class curr_alt[MAX_RECOG_OPERANDS]; + HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS]; + bool curr_alt_match_win[MAX_RECOG_OPERANDS]; + bool curr_alt_win[MAX_RECOG_OPERANDS]; + bool curr_alt_offmemok[MAX_RECOG_OPERANDS]; + int curr_alt_matches[MAX_RECOG_OPERANDS]; + /* The number of elements in the following array. */ + int curr_alt_dont_inherit_ops_num; + /* Numbers of operands whose reload pseudos should not be inherited. */ + int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; + rtx op; + /* The register when the operand is a subreg of register, otherwise the + operand itself. */ + rtx no_subreg_reg_operand[MAX_RECOG_OPERANDS]; + /* The register if the operand is a register or subreg of register, + otherwise NULL. */ + rtx operand_reg[MAX_RECOG_OPERANDS]; + int hard_regno[MAX_RECOG_OPERANDS]; + enum machine_mode biggest_mode[MAX_RECOG_OPERANDS]; + int reload_nregs, reload_sum; + bool costly_p; + enum reg_class cl; + + /* Calculate some data common for all alternatives to speed up the + function. */ + for (nop = 0; nop < n_operands; nop++) + { + op = no_subreg_reg_operand[nop] = *curr_id->operand_loc[nop]; + /* The real hard regno of the operand after the allocation. */ + hard_regno[nop] = get_hard_regno (op); + + operand_reg[nop] = op; + biggest_mode[nop] = GET_MODE (operand_reg[nop]); + if (GET_CODE (operand_reg[nop]) == SUBREG) + { + operand_reg[nop] = SUBREG_REG (operand_reg[nop]); + if (GET_MODE_SIZE (biggest_mode[nop]) + < GET_MODE_SIZE (GET_MODE (operand_reg[nop]))) + biggest_mode[nop] = GET_MODE (operand_reg[nop]); + } + if (REG_P (operand_reg[nop])) + no_subreg_reg_operand[nop] = operand_reg[nop]; + else + operand_reg[nop] = NULL_RTX; + } + + /* The constraints are made of several alternatives. Each operand's + constraint looks like foo,bar,... with commas separating the + alternatives. The first alternatives for all operands go + together, the second alternatives go together, etc. + + First loop over alternatives. */ + for (nalt = 0; nalt < n_alternatives; nalt++) + { + /* Loop over operands for one constraint alternative. */ +#ifdef HAVE_ATTR_enabled + if (curr_id->alternative_enabled_p != NULL + && ! curr_id->alternative_enabled_p[nalt]) + continue; +#endif + + if (only_alternative >= 0 && nalt != only_alternative) + continue; + + overall = losers = reject = reload_nregs = reload_sum = 0; + for (nop = 0; nop < n_operands; nop++) + reject += (curr_static_id + ->operand_alternative[nalt * n_operands + nop].reject); + early_clobbered_regs_num = 0; + + for (nop = 0; nop < n_operands; nop++) + { + const char *p; + char *end; + int len, c, m, i, opalt_num, this_alternative_matches; + bool win, did_match, offmemok, early_clobber_p; + /* false => this operand can be reloaded somehow for this + alternative. */ + bool badop; + /* true => this operand can be reloaded if the alternative + allows regs. */ + bool winreg; + /* True if a constant forced into memory would be OK for + this operand. */ + bool constmemok; + enum reg_class this_alternative, this_costly_alternative; + HARD_REG_SET this_alternative_set, this_costly_alternative_set; + bool this_alternative_match_win, this_alternative_win; + bool this_alternative_offmemok; + enum machine_mode mode; + + opalt_num = nalt * n_operands + nop; + if (curr_static_id->operand_alternative[opalt_num].anything_ok) + { + /* Fast track for no constraints at all. */ + curr_alt[nop] = NO_REGS; + CLEAR_HARD_REG_SET (curr_alt_set[nop]); + curr_alt_win[nop] = true; + curr_alt_match_win[nop] = false; + curr_alt_offmemok[nop] = false; + curr_alt_matches[nop] = -1; + continue; + } + + op = no_subreg_reg_operand[nop]; + mode = curr_operand_mode[nop]; + + win = did_match = winreg = offmemok = constmemok = false; + badop = true; + + early_clobber_p = false; + p = curr_static_id->operand_alternative[opalt_num].constraint; + + this_costly_alternative = this_alternative = NO_REGS; + /* We update set of possible hard regs besides its class + because reg class might be inaccurate. For example, + union of LO_REGS (l), HI_REGS(h), and STACK_REG(k) in ARM + is translated in HI_REGS because classes are merged by + pairs and there is no accurate intermediate class. */ + CLEAR_HARD_REG_SET (this_alternative_set); + CLEAR_HARD_REG_SET (this_costly_alternative_set); + this_alternative_win = false; + this_alternative_match_win = false; + this_alternative_offmemok = false; + this_alternative_matches = -1; + + /* An empty constraint should be excluded by the fast + track. */ + lra_assert (*p != 0 && *p != ','); + + /* Scan this alternative's specs for this operand; set WIN + if the operand fits any letter in this alternative. + Otherwise, clear BADOP if this operand could fit some + letter after reloads, or set WINREG if this operand could + fit after reloads provided the constraint allows some + registers. */ + costly_p = false; + do + { + switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) + { + case '\0': + len = 0; + break; + case ',': + c = '\0'; + break; + + case '=': case '+': case '?': case '*': case '!': + case ' ': case '\t': + break; + + case '%': + /* We only support one commutative marker, the first + one. We already set commutative above. */ + break; + + case '&': + early_clobber_p = true; + break; + + case '#': + /* Ignore rest of this alternative. */ + c = '\0'; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int m_hregno; + bool match_p; + + m = strtoul (p, &end, 10); + p = end; + len = 0; + lra_assert (nop > m); + + this_alternative_matches = m; + m_hregno = get_hard_regno (*curr_id->operand_loc[m]); + /* We are supposed to match a previous operand. + If we do, we win if that one did. If we do + not, count both of the operands as losers. + (This is too conservative, since most of the + time only a single reload insn will be needed + to make the two operands win. As a result, + this alternative may be rejected when it is + actually desirable.) */ + match_p = false; + if (operands_match_p (*curr_id->operand_loc[nop], + *curr_id->operand_loc[m], m_hregno)) + { + /* We should reject matching of an early + clobber operand if the matching operand is + not dying in the insn. */ + if (! curr_static_id->operand[m].early_clobber + || operand_reg[nop] == NULL_RTX + || (find_regno_note (curr_insn, REG_DEAD, + REGNO (operand_reg[nop])) + != NULL_RTX)) + match_p = true; + } + if (match_p) + { + /* If we are matching a non-offsettable + address where an offsettable address was + expected, then we must reject this + combination, because we can't reload + it. */ + if (curr_alt_offmemok[m] + && MEM_P (*curr_id->operand_loc[m]) + && curr_alt[m] == NO_REGS && ! curr_alt_win[m]) + continue; + + } + else + { + /* Operands don't match. Both operands must + allow a reload register, otherwise we + cannot make them match. */ + if (curr_alt[m] == NO_REGS) + break; + /* Retroactively mark the operand we had to + match as a loser, if it wasn't already and + it wasn't matched to a register constraint + (e.g it might be matched by memory). */ + if (curr_alt_win[m] + && (operand_reg[m] == NULL_RTX + || hard_regno[m] < 0)) + { + losers++; + reload_nregs + += (ira_reg_class_max_nregs[curr_alt[m]] + [GET_MODE (*curr_id->operand_loc[m])]); + } + + /* We prefer no matching alternatives because + it gives more freedom in RA. */ + if (operand_reg[nop] == NULL_RTX + || (find_regno_note (curr_insn, REG_DEAD, + REGNO (operand_reg[nop])) + == NULL_RTX)) + reject += 2; + } + /* If we have to reload this operand and some + previous operand also had to match the same + thing as this operand, we don't know how to do + that. */ + if (!match_p || !curr_alt_win[m]) + { + for (i = 0; i < nop; i++) + if (curr_alt_matches[i] == m) + break; + if (i < nop) + break; + } + else + did_match = true; + + /* This can be fixed with reloads if the operand + we are supposed to match can be fixed with + reloads. */ + badop = false; + this_alternative = curr_alt[m]; + COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]); + break; + } + + case 'p': + cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH); + this_alternative = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + win = true; + badop = false; + break; + + case TARGET_MEM_CONSTRAINT: + if (MEM_P (op) || spilled_pseudo_p (op)) + win = true; + if (CONST_POOL_OK_P (mode, op)) + badop = false; + constmemok = true; + break; + + case '<': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || GET_CODE (XEXP (op, 0)) == POST_DEC)) + win = true; + break; + + case '>': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_INC + || GET_CODE (XEXP (op, 0)) == POST_INC)) + win = true; + break; + + /* Memory op whose address is not offsettable. */ + case 'V': + if (MEM_P (op) + && ! offsettable_nonstrict_memref_p (op)) + win = true; + break; + + /* Memory operand whose address is offsettable. */ + case 'o': + if ((MEM_P (op) + && offsettable_nonstrict_memref_p (op)) + || spilled_pseudo_p (op)) + win = true; + if (CONST_POOL_OK_P (mode, op) || MEM_P (op)) + badop = false; + constmemok = true; + offmemok = true; + break; + + case 'E': + case 'F': + if (GET_CODE (op) == CONST_DOUBLE + || (GET_CODE (op) == CONST_VECTOR + && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT))) + win = true; + break; + + case 'G': + case 'H': + if (GET_CODE (op) == CONST_DOUBLE + && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) + win = true; + break; + + case 's': + if (CONST_INT_P (op) + || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)) + break; + case 'i': + if (general_constant_p (op)) + win = true; + break; + + case 'n': + if (CONST_INT_P (op) + || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)) + win = true; + break; + + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + if (CONST_INT_P (op) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) + win = true; + break; + + case 'X': + /* This constraint should be excluded by the fast + track. */ + gcc_unreachable (); + break; + + case 'g': + if (MEM_P (op) + || general_constant_p (op) + || spilled_pseudo_p (op)) + win = true; + /* Drop through into 'r' case. */ + + case 'r': + this_alternative + = reg_class_subunion[this_alternative][GENERAL_REGS]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[GENERAL_REGS]); + if (costly_p) + { + this_costly_alternative + = (reg_class_subunion + [this_costly_alternative][GENERAL_REGS]); + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[GENERAL_REGS]); + } + goto reg; + + default: + if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) + { +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_MEMORY_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + else if (spilled_pseudo_p (op)) + win = true; + + /* If we didn't already win, we can reload + constants via force_const_mem, and other + MEMs by reloading the address like for + 'o'. */ + if (CONST_POOL_OK_P (mode, op) || MEM_P (op)) + badop = false; + constmemok = true; + offmemok = true; + break; + } + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + + /* If we didn't already win, we can reload + the address into a base register. */ + cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH); + this_alternative + = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = (reg_class_subunion + [this_costly_alternative][cl]); + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + badop = false; + break; + } + + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; +#endif + break; + } + + cl = REG_CLASS_FROM_CONSTRAINT (c, p); + this_alternative = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + reg: + if (mode == BLKmode) + break; + winreg = true; + if (REG_P (op)) + { + if (hard_regno[nop] >= 0 + && in_hard_reg_set_p (this_alternative_set, + mode, hard_regno[nop])) + win = true; + else if (hard_regno[nop] < 0 + && in_class_p (op, this_alternative, NULL)) + win = true; + } + break; + } + if (c != ' ' && c != '\t') + costly_p = c == '*'; + } + while ((p += len), c); + + /* Record which operands fit this alternative. */ + if (win) + { + this_alternative_win = true; + if (operand_reg[nop] != NULL_RTX) + { + if (hard_regno[nop] >= 0) + { + if (in_hard_reg_set_p (this_costly_alternative_set, + mode, hard_regno[nop])) + reject++; + } + else + { + /* Prefer won reg to spilled pseudo under other equal + conditions. */ + reject++; + if (in_class_p (operand_reg[nop], + this_costly_alternative, NULL)) + reject++; + } + /* We simulate the behaviour of old reload here. + Although scratches need hard registers and it + might result in spilling other pseudos, no reload + insns are generated for the scratches. So it + might cost something but probably less than old + reload pass believes. */ + if (lra_former_scratch_p (REGNO (operand_reg[nop]))) + reject += LOSER_COST_FACTOR; + } + } + else if (did_match) + this_alternative_match_win = true; + else + { + int const_to_mem = 0; + bool no_regs_p; + + no_regs_p + = (this_alternative == NO_REGS + || (hard_reg_set_subset_p + (reg_class_contents[this_alternative], + lra_no_alloc_regs))); + /* If this operand accepts a register, and if the + register class has at least one allocatable register, + then this operand can be reloaded. */ + if (winreg && !no_regs_p) + badop = false; + + if (badop) + goto fail; + + this_alternative_offmemok = offmemok; + if (this_costly_alternative != NO_REGS) + reject++; + /* If the operand is dying, has a matching constraint, + and satisfies constraints of the matched operand + which failed to satisfy the own constraints, we do + not need to generate a reload insn for this + operand. */ + if (!(this_alternative_matches >= 0 + && !curr_alt_win[this_alternative_matches] + && REG_P (op) + && find_regno_note (curr_insn, REG_DEAD, REGNO (op)) + && (hard_regno[nop] >= 0 + ? in_hard_reg_set_p (this_alternative_set, + mode, hard_regno[nop]) + : in_class_p (op, this_alternative, NULL)))) + losers++; + if (operand_reg[nop] != NULL_RTX + /* Output operands and matched input operands are + not inherited. The following conditions do not + exactly describe the previous statement but they + are pretty close. */ + && curr_static_id->operand[nop].type != OP_OUT + && (this_alternative_matches < 0 + || curr_static_id->operand[nop].type != OP_IN)) + { + int last_reload = (lra_reg_info[ORIGINAL_REGNO + (operand_reg[nop])] + .last_reload); + + if (last_reload > bb_reload_num) + reload_sum += last_reload - bb_reload_num; + } + /* If this is a constant that is reloaded into the + desired class by copying it to memory first, count + that as another reload. This is consistent with + other code and is required to avoid choosing another + alternative when the constant is moved into memory. + Note that the test here is precisely the same as in + the code below that calls force_const_mem. */ + if (CONST_POOL_OK_P (mode, op) + && ((targetm.preferred_reload_class + (op, this_alternative) == NO_REGS) + || no_input_reloads_p)) + { + const_to_mem = 1; + if (! no_regs_p) + losers++; + } + + /* Alternative loses if it requires a type of reload not + permitted for this insn. We can always reload + objects with a REG_UNUSED note. */ + if ((curr_static_id->operand[nop].type != OP_IN + && no_output_reloads_p + && ! find_reg_note (curr_insn, REG_UNUSED, op)) + || (curr_static_id->operand[nop].type != OP_OUT + && no_input_reloads_p && ! const_to_mem)) + goto fail; + + /* If we can't reload this value at all, reject this + alternative. Note that we could also lose due to + LIMIT_RELOAD_CLASS, but we don't check that here. */ + if (! CONSTANT_P (op) && ! no_regs_p) + { + if (targetm.preferred_reload_class + (op, this_alternative) == NO_REGS) + reject = MAX_OVERALL_COST_BOUND; + + if (curr_static_id->operand[nop].type == OP_OUT + && (targetm.preferred_output_reload_class + (op, this_alternative) == NO_REGS)) + reject = MAX_OVERALL_COST_BOUND; + } + + if (! ((const_to_mem && constmemok) + || (MEM_P (op) && offmemok))) + { + /* We prefer to reload pseudos over reloading other + things, since such reloads may be able to be + eliminated later. So bump REJECT in other cases. + Don't do this in the case where we are forcing a + constant into memory and it will then win since + we don't want to have a different alternative + match then. */ + if (! (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)) + reject += 2; + + if (! no_regs_p) + reload_nregs + += ira_reg_class_max_nregs[this_alternative][mode]; + } + + /* Input reloads can be inherited more often than output + reloads can be removed, so penalize output + reloads. */ + if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN) + reject++; + } + + if (early_clobber_p) + reject++; + /* ??? We check early clobbers after processing all operands + (see loop below) and there we update the costs more. + Should we update the cost (may be approximately) here + because of early clobber register reloads or it is a rare + or non-important thing to be worth to do it. */ + overall = losers * LOSER_COST_FACTOR + reject; + if ((best_losers == 0 || losers != 0) && best_overall < overall) + goto fail; + + curr_alt[nop] = this_alternative; + COPY_HARD_REG_SET (curr_alt_set[nop], this_alternative_set); + curr_alt_win[nop] = this_alternative_win; + curr_alt_match_win[nop] = this_alternative_match_win; + curr_alt_offmemok[nop] = this_alternative_offmemok; + curr_alt_matches[nop] = this_alternative_matches; + + if (this_alternative_matches >= 0 + && !did_match && !this_alternative_win) + curr_alt_win[this_alternative_matches] = false; + + if (early_clobber_p && operand_reg[nop] != NULL_RTX) + early_clobbered_nops[early_clobbered_regs_num++] = nop; + } + ok_p = true; + curr_alt_dont_inherit_ops_num = 0; + for (nop = 0; nop < early_clobbered_regs_num; nop++) + { + int i, j, clobbered_hard_regno; + HARD_REG_SET temp_set; + + i = early_clobbered_nops[nop]; + if ((! curr_alt_win[i] && ! curr_alt_match_win[i]) + || hard_regno[i] < 0) + continue; + clobbered_hard_regno = hard_regno[i]; + CLEAR_HARD_REG_SET (temp_set); + add_to_hard_reg_set (&temp_set, biggest_mode[i], clobbered_hard_regno); + for (j = 0; j < n_operands; j++) + if (j == i + /* We don't want process insides of match_operator and + match_parallel because otherwise we would process + their operands once again generating a wrong + code. */ + || curr_static_id->operand[j].is_operator) + continue; + else if ((curr_alt_matches[j] == i && curr_alt_match_win[j]) + || (curr_alt_matches[i] == j && curr_alt_match_win[i])) + continue; + else if (uses_hard_regs_p (*curr_id->operand_loc[j], temp_set)) + break; + if (j >= n_operands) + continue; + /* We need to reload early clobbered register. */ + for (j = 0; j < n_operands; j++) + if (curr_alt_matches[j] == i) + { + curr_alt_match_win[j] = false; + losers++; + overall += LOSER_COST_FACTOR; + } + if (! curr_alt_match_win[i]) + curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i; + else + { + /* Remember pseudos used for match reloads are never + inherited. */ + lra_assert (curr_alt_matches[i] >= 0); + curr_alt_win[curr_alt_matches[i]] = false; + } + curr_alt_win[i] = curr_alt_match_win[i] = false; + losers++; + overall += LOSER_COST_FACTOR; + } + small_class_operands_num = 0; + for (nop = 0; nop < n_operands; nop++) + small_class_operands_num + += SMALL_REGISTER_CLASS_P (curr_alt[nop]) ? 1 : 0; + + /* If this alternative can be made to work by reloading, and it + needs less reloading than the others checked so far, record + it as the chosen goal for reloading. */ + if ((best_losers != 0 && losers == 0) + || (((best_losers == 0 && losers == 0) + || (best_losers != 0 && losers != 0)) + && (best_overall > overall + || (best_overall == overall + /* If the cost of the reloads is the same, + prefer alternative which requires minimal + number of small register classes for the + operands. This improves chances of reloads + for insn requiring small register + classes. */ + && (small_class_operands_num + < best_small_class_operands_num + || (small_class_operands_num + == best_small_class_operands_num + && (reload_nregs < best_reload_nregs + || (reload_nregs == best_reload_nregs + && best_reload_sum < reload_sum)))))))) + { + for (nop = 0; nop < n_operands; nop++) + { + goal_alt_win[nop] = curr_alt_win[nop]; + goal_alt_match_win[nop] = curr_alt_match_win[nop]; + goal_alt_matches[nop] = curr_alt_matches[nop]; + goal_alt[nop] = curr_alt[nop]; + goal_alt_offmemok[nop] = curr_alt_offmemok[nop]; + } + goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num; + for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++) + goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop]; + goal_alt_swapped = curr_swapped; + best_overall = overall; + best_losers = losers; + best_small_class_operands_num = small_class_operands_num; + best_reload_nregs = reload_nregs; + best_reload_sum = reload_sum; + goal_alt_number = nalt; + } + if (losers == 0) + /* Everything is satisfied. Do not process alternatives + anymore. */ + break; + fail: + ; + } + return ok_p; +} + +/* Return 1 if ADDR is a valid memory address for mode MODE in address + space AS, and check that each pseudo has the proper kind of hard + reg. */ +static int +valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx addr, addr_space_t as) +{ +#ifdef GO_IF_LEGITIMATE_ADDRESS + lra_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, 0, as); +#endif +} + +/* Make reload base reg + disp from address AD in space AS of memory + with MODE into a new pseudo. Return the new pseudo. */ +static rtx +base_plus_disp_to_reg (enum machine_mode mode, addr_space_t as, + struct address *ad) +{ + enum reg_class cl; + rtx new_reg; + + lra_assert (ad->base_reg_loc != NULL && ad->disp_loc != NULL); + cl = base_reg_class (mode, as, ad->base_outer_code, ad->index_code); + new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "base + disp"); + lra_emit_add (new_reg, *ad->base_reg_loc, *ad->disp_loc); + return new_reg; +} + +/* Make substitution in address AD in space AS with location ADDR_LOC. + Update AD and ADDR_LOC if it is necessary. Return true if a + substitution was made. */ +static bool +equiv_address_substitution (struct address *ad, rtx *addr_loc, + enum machine_mode mode, addr_space_t as, + enum rtx_code code) +{ + rtx base_reg, new_base_reg, index_reg, new_index_reg; + HOST_WIDE_INT disp, scale; + bool change_p; + + if (ad->base_reg_loc == NULL) + base_reg = new_base_reg = NULL_RTX; + else + { + base_reg = *ad->base_reg_loc; + new_base_reg = get_equiv_substitution (base_reg); + } + if (ad->index_reg_loc == NULL) + index_reg = new_index_reg = NULL_RTX; + else + { + index_reg = *ad->index_reg_loc; + new_index_reg = get_equiv_substitution (index_reg); + } + if (base_reg == new_base_reg && index_reg == new_index_reg) + return false; + disp = 0; + change_p = false; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, "Changing address in insn %d ", + INSN_UID (curr_insn)); + print_value_slim (lra_dump_file, *addr_loc, 1); + } + if (base_reg != new_base_reg) + { + if (REG_P (new_base_reg)) + { + *ad->base_reg_loc = new_base_reg; + change_p = true; + } + else if (GET_CODE (new_base_reg) == PLUS + && REG_P (XEXP (new_base_reg, 0)) + && CONST_INT_P (XEXP (new_base_reg, 1))) + { + disp += INTVAL (XEXP (new_base_reg, 1)); + *ad->base_reg_loc = XEXP (new_base_reg, 0); + change_p = true; + } + if (ad->base_reg_loc2 != NULL) + *ad->base_reg_loc2 = *ad->base_reg_loc; + } + scale = 1; + if (ad->index_loc != NULL && GET_CODE (*ad->index_loc) == MULT) + { + lra_assert (CONST_INT_P (XEXP (*ad->index_loc, 1))); + scale = INTVAL (XEXP (*ad->index_loc, 1)); + } + if (index_reg != new_index_reg) + { + if (REG_P (new_index_reg)) + { + *ad->index_reg_loc = new_index_reg; + change_p = true; + } + else if (GET_CODE (new_index_reg) == PLUS + && REG_P (XEXP (new_index_reg, 0)) + && CONST_INT_P (XEXP (new_index_reg, 1))) + { + disp += INTVAL (XEXP (new_index_reg, 1)) * scale; + *ad->index_reg_loc = XEXP (new_index_reg, 0); + change_p = true; + } + } + if (disp != 0) + { + if (ad->disp_loc != NULL) + *ad->disp_loc = plus_constant (Pmode, *ad->disp_loc, disp); + else + { + *addr_loc = gen_rtx_PLUS (Pmode, *addr_loc, GEN_INT (disp)); + extract_address_regs (mode, as, addr_loc, code, ad); + } + change_p = true; + } + if (lra_dump_file != NULL) + { + if (! change_p) + fprintf (lra_dump_file, " -- no change\n"); + else + { + fprintf (lra_dump_file, " on equiv "); + print_value_slim (lra_dump_file, *addr_loc, 1); + fprintf (lra_dump_file, "\n"); + } + } + return change_p; +} + +/* Major function to make reloads for address in operand NOP. Add to + reloads to the list *BEFORE and *AFTER. We might need to add + reloads to *AFTER because of inc/dec, {pre, post} modify in the + address. Return true for any RTL change. */ +static bool +process_address (int nop, rtx *before, rtx *after) +{ + struct address ad; + enum machine_mode mode; + rtx new_reg, *addr_loc, saved_index_reg, saved_base_reg; + bool ok_p; + addr_space_t as; + rtx op = *curr_id->operand_loc[nop]; + const char *constraint = curr_static_id->operand[nop].constraint; + bool change_p; + enum rtx_code code; + + if (constraint[0] == 'p' + || EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint)) + { + mode = VOIDmode; + addr_loc = curr_id->operand_loc[nop]; + as = ADDR_SPACE_GENERIC; + code = ADDRESS; + } + else if (MEM_P (op)) + { + mode = GET_MODE (op); + addr_loc = &XEXP (op, 0); + as = MEM_ADDR_SPACE (op); + code = MEM; + } + else if (GET_CODE (op) == SUBREG + && MEM_P (SUBREG_REG (op))) + { + mode = GET_MODE (SUBREG_REG (op)); + addr_loc = &XEXP (SUBREG_REG (op), 0); + as = MEM_ADDR_SPACE (SUBREG_REG (op)); + code = MEM; + } + else + return false; + if (GET_CODE (*addr_loc) == AND) + addr_loc = &XEXP (*addr_loc, 0); + extract_address_regs (mode, as, addr_loc, code, &ad); + change_p = equiv_address_substitution (&ad, addr_loc, mode, as, code); + if (ad.base_reg_loc != NULL + && (process_addr_reg + (ad.base_reg_loc, before, + (ad.base_modify_p && REG_P (*ad.base_reg_loc) + && find_regno_note (curr_insn, REG_DEAD, + REGNO (*ad.base_reg_loc)) == NULL_RTX + ? after : NULL), + base_reg_class (mode, as, ad.base_outer_code, ad.index_code)))) + { + change_p = true; + if (ad.base_reg_loc2 != NULL) + *ad.base_reg_loc2 = *ad.base_reg_loc; + } + if (ad.index_reg_loc != NULL + && process_addr_reg (ad.index_reg_loc, before, NULL, INDEX_REG_CLASS)) + change_p = true; + + /* The address was valid before LRA. We only change its form if the + address has a displacement, so if it has no displacement it must + still be valid. */ + if (ad.disp_loc == NULL) + return change_p; + + /* See whether the address is still valid. Some ports do not check + displacements for eliminable registers, so we replace them + temporarily with the elimination target. */ + saved_base_reg = saved_index_reg = NULL_RTX; + if (ad.base_reg_loc != NULL) + { + saved_base_reg = *ad.base_reg_loc; + lra_eliminate_reg_if_possible (ad.base_reg_loc); + if (ad.base_reg_loc2 != NULL) + *ad.base_reg_loc2 = *ad.base_reg_loc; + } + if (ad.index_reg_loc != NULL) + { + saved_index_reg = *ad.index_reg_loc; + lra_eliminate_reg_if_possible (ad.index_reg_loc); + } + /* Some ports do not check displacements for virtual registers -- so + we substitute them temporarily by real registers. */ + ok_p = valid_address_p (mode, *addr_loc, as); + if (saved_base_reg != NULL_RTX) + { + *ad.base_reg_loc = saved_base_reg; + if (ad.base_reg_loc2 != NULL) + *ad.base_reg_loc2 = saved_base_reg; + } + if (saved_index_reg != NULL_RTX) + *ad.index_reg_loc = saved_index_reg; + + if (ok_p) + return change_p; + + /* Addresses were legitimate before LRA. So if the address has + two registers than it can have two of them. We should also + not worry about scale for the same reason. */ + push_to_sequence (*before); + if (ad.base_reg_loc == NULL) + { + if (ad.index_reg_loc == NULL) + { + int code = -1; + enum reg_class cl = base_reg_class (mode, as, SCRATCH, SCRATCH); + + new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp"); +#ifdef HAVE_lo_sum + { + rtx insn; + rtx last = get_last_insn (); + + /* disp => lo_sum (new_base, disp) */ + insn = emit_insn (gen_rtx_SET + (VOIDmode, new_reg, + gen_rtx_HIGH (Pmode, copy_rtx (*ad.disp_loc)))); + code = recog_memoized (insn); + if (code >= 0) + { + rtx save = *ad.disp_loc; + + *ad.disp_loc = gen_rtx_LO_SUM (Pmode, new_reg, *ad.disp_loc); + if (! valid_address_p (mode, *ad.disp_loc, as)) + { + *ad.disp_loc = save; + code = -1; + } + } + if (code < 0) + delete_insns_since (last); + } +#endif + if (code < 0) + { + /* disp => new_base */ + lra_emit_move (new_reg, *ad.disp_loc); + *ad.disp_loc = new_reg; + } + } + else + { + /* index * scale + disp => new base + index * scale */ + enum reg_class cl = base_reg_class (mode, as, SCRATCH, SCRATCH); + + lra_assert (INDEX_REG_CLASS != NO_REGS); + new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp"); + lra_assert (GET_CODE (*addr_loc) == PLUS); + lra_emit_move (new_reg, *ad.disp_loc); + if (CONSTANT_P (XEXP (*addr_loc, 1))) + XEXP (*addr_loc, 1) = XEXP (*addr_loc, 0); + XEXP (*addr_loc, 0) = new_reg; + } + } + else if (ad.index_reg_loc == NULL) + { + /* base + disp => new base */ + /* Another option would be to reload the displacement into an + index register. However, postreload has code to optimize + address reloads that have the same base and different + displacements, so reloading into an index register would + not necessarily be a win. */ + new_reg = base_plus_disp_to_reg (mode, as, &ad); + *addr_loc = new_reg; + } + else + { + /* base + scale * index + disp => new base + scale * index */ + new_reg = base_plus_disp_to_reg (mode, as, &ad); + *addr_loc = gen_rtx_PLUS (Pmode, new_reg, *ad.index_loc); + } + *before = get_insns (); + end_sequence (); + return true; +} + +/* Emit insns to reload VALUE into a new register. VALUE is an + auto-increment or auto-decrement RTX whose operand is a register or + memory location; so reloading involves incrementing that location. + IN is either identical to VALUE, or some cheaper place to reload + value being incremented/decremented from. + + INC_AMOUNT is the number to increment or decrement by (always + positive and ignored for POST_MODIFY/PRE_MODIFY). + + Return pseudo containing the result. */ +static rtx +emit_inc (enum reg_class new_rclass, rtx in, rtx value, int inc_amount) +{ + /* REG or MEM to be copied and incremented. */ + rtx incloc = XEXP (value, 0); + /* Nonzero if increment after copying. */ + int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC + || GET_CODE (value) == POST_MODIFY); + rtx last; + rtx inc; + rtx add_insn; + int code; + rtx real_in = in == value ? incloc : in; + rtx result; + bool plus_p = true; + + if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY) + { + lra_assert (GET_CODE (XEXP (value, 1)) == PLUS + || GET_CODE (XEXP (value, 1)) == MINUS); + lra_assert (rtx_equal_p (XEXP (XEXP (value, 1), 0), XEXP (value, 0))); + plus_p = GET_CODE (XEXP (value, 1)) == PLUS; + inc = XEXP (XEXP (value, 1), 1); + } + else + { + if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC) + inc_amount = -inc_amount; + + inc = GEN_INT (inc_amount); + } + + if (! post && REG_P (incloc)) + result = incloc; + else + result = lra_create_new_reg (GET_MODE (value), value, new_rclass, + "INC/DEC result"); + + if (real_in != result) + { + /* First copy the location to the result register. */ + lra_assert (REG_P (result)); + emit_insn (gen_move_insn (result, real_in)); + } + + /* We suppose that there are insns to add/sub with the constant + increment permitted in {PRE/POST)_{DEC/INC/MODIFY}. At least the + old reload worked with this assumption. If the assumption + becomes wrong, we should use approach in function + base_plus_disp_to_reg. */ + if (in == value) + { + /* See if we can directly increment INCLOC. */ + last = get_last_insn (); + add_insn = emit_insn (plus_p + ? gen_add2_insn (incloc, inc) + : gen_sub2_insn (incloc, inc)); + + code = recog_memoized (add_insn); + if (code >= 0) + { + if (! post && result != incloc) + emit_insn (gen_move_insn (result, incloc)); + return result; + } + delete_insns_since (last); + } + + /* If couldn't do the increment directly, must increment in RESULT. + The way we do this depends on whether this is pre- or + post-increment. For pre-increment, copy INCLOC to the reload + register, increment it there, then save back. */ + if (! post) + { + if (real_in != result) + emit_insn (gen_move_insn (result, real_in)); + if (plus_p) + emit_insn (gen_add2_insn (result, inc)); + else + emit_insn (gen_sub2_insn (result, inc)); + if (result != incloc) + emit_insn (gen_move_insn (incloc, result)); + } + else + { + /* Post-increment. + + Because this might be a jump insn or a compare, and because + RESULT may not be available after the insn in an input + reload, we must do the incrementing before the insn being + reloaded for. + + We have already copied IN to RESULT. Increment the copy in + RESULT, save that back, then decrement RESULT so it has + the original value. */ + if (plus_p) + emit_insn (gen_add2_insn (result, inc)); + else + emit_insn (gen_sub2_insn (result, inc)); + emit_insn (gen_move_insn (incloc, result)); + /* Restore non-modified value for the result. We prefer this + way because it does not require an additional hard + register. */ + if (plus_p) + { + if (CONST_INT_P (inc)) + emit_insn (gen_add2_insn (result, GEN_INT (-INTVAL (inc)))); + else + emit_insn (gen_sub2_insn (result, inc)); + } + else + emit_insn (gen_add2_insn (result, inc)); + } + return result; +} + +/* Swap operands NOP and NOP + 1. */ +static inline void +swap_operands (int nop) +{ + enum machine_mode mode = curr_operand_mode[nop]; + curr_operand_mode[nop] = curr_operand_mode[nop + 1]; + curr_operand_mode[nop + 1] = mode; + rtx x = *curr_id->operand_loc[nop]; + *curr_id->operand_loc[nop] = *curr_id->operand_loc[nop + 1]; + *curr_id->operand_loc[nop + 1] = x; + /* Swap the duplicates too. */ + lra_update_dup (curr_id, nop); + lra_update_dup (curr_id, nop + 1); +} + +/* Main entry point of the constraint code: search the body of the + current insn to choose the best alternative. It is mimicking insn + alternative cost calculation model of former reload pass. That is + because machine descriptions were written to use this model. This + model can be changed in future. Make commutative operand exchange + if it is chosen. + + Return true if some RTL changes happened during function call. */ +static bool +curr_insn_transform (void) +{ + int i, j, k; + int n_operands; + int n_alternatives; + int commutative; + signed char goal_alt_matched[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS]; + rtx before, after; + bool alt_p = false; + /* Flag that the insn has been changed through a transformation. */ + bool change_p; + bool sec_mem_p; +#ifdef SECONDARY_MEMORY_NEEDED + bool use_sec_mem_p; +#endif + int max_regno_before; + int reused_alternative_num; + + no_input_reloads_p = no_output_reloads_p = false; + goal_alt_number = -1; + + if (check_and_process_move (&change_p, &sec_mem_p)) + return change_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 (curr_insn) || CALL_P (curr_insn)) + no_output_reloads_p = true; + +#ifdef HAVE_cc0 + if (reg_referenced_p (cc0_rtx, PATTERN (curr_insn))) + no_input_reloads_p = true; + if (reg_set_p (cc0_rtx, PATTERN (curr_insn))) + no_output_reloads_p = true; +#endif + + n_operands = curr_static_id->n_operands; + n_alternatives = curr_static_id->n_alternatives; + + /* Just return "no reloads" if insn has no operands with + constraints. */ + if (n_operands == 0 || n_alternatives == 0) + return false; + + max_regno_before = max_reg_num (); + + for (i = 0; i < n_operands; i++) + { + goal_alt_matched[i][0] = -1; + goal_alt_matches[i] = -1; + } + + commutative = curr_static_id->commutative; + + /* Now see what we need for pseudos that didn't get hard regs or got + the wrong kind of hard reg. For this, we must consider all the + operands together against the register constraints. */ + + best_losers = best_overall = MAX_RECOG_OPERANDS * 2 + MAX_OVERALL_COST_BOUND; + best_small_class_operands_num = best_reload_sum = 0; + + curr_swapped = false; + goal_alt_swapped = false; + + /* Make equivalence substitution and memory subreg elimination + before address processing because an address legitimacy can + depend on memory mode. */ + for (i = 0; i < n_operands; i++) + { + rtx op = *curr_id->operand_loc[i]; + rtx subst, old = op; + bool op_change_p = false; + + if (GET_CODE (old) == SUBREG) + old = SUBREG_REG (old); + subst = get_equiv_substitution (old); + if (subst != old) + { + subst = copy_rtx (subst); + lra_assert (REG_P (old)); + if (GET_CODE (op) == SUBREG) + SUBREG_REG (op) = subst; + else + *curr_id->operand_loc[i] = subst; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + "Changing pseudo %d in operand %i of insn %u on equiv ", + REGNO (old), i, INSN_UID (curr_insn)); + print_value_slim (lra_dump_file, subst, 1); + fprintf (lra_dump_file, "\n"); + } + op_change_p = change_p = true; + } + if (simplify_operand_subreg (i, GET_MODE (old)) || op_change_p) + { + change_p = true; + lra_update_dup (curr_id, i); + } + } + + /* Reload address registers and displacements. We do it before + finding an alternative because of memory constraints. */ + before = after = NULL_RTX; + for (i = 0; i < n_operands; i++) + if (! curr_static_id->operand[i].is_operator + && process_address (i, &before, &after)) + { + change_p = true; + lra_update_dup (curr_id, i); + } + + if (change_p) + /* If we've changed the instruction then any alternative that + we chose previously may no longer be valid. */ + lra_set_used_insn_alternative (curr_insn, -1); + + try_swapped: + + reused_alternative_num = curr_id->used_insn_alternative; + if (lra_dump_file != NULL && reused_alternative_num >= 0) + fprintf (lra_dump_file, "Reusing alternative %d for insn #%u\n", + reused_alternative_num, INSN_UID (curr_insn)); + + if (process_alt_operands (reused_alternative_num)) + alt_p = true; + + /* If insn is commutative (it's safe to exchange a certain pair of + operands) then we need to try each alternative twice, the second + time matching those two operands as if we had exchanged them. To + do this, really exchange them in operands. + + If we have just tried the alternatives the second time, return + operands to normal and drop through. */ + + if (reused_alternative_num < 0 && commutative >= 0) + { + curr_swapped = !curr_swapped; + if (curr_swapped) + { + swap_operands (commutative); + goto try_swapped; + } + else + swap_operands (commutative); + } + + /* The operands don't meet the constraints. goal_alt describes the + alternative that we could reach by reloading the fewest operands. + Reload so as to fit it. */ + + if (! alt_p && ! sec_mem_p) + { + /* No alternative works with reloads?? */ + if (INSN_CODE (curr_insn) >= 0) + fatal_insn ("unable to generate reloads for:", curr_insn); + error_for_asm (curr_insn, + "inconsistent operand constraints in an %<asm%>"); + /* Avoid further trouble with this insn. */ + PATTERN (curr_insn) = gen_rtx_USE (VOIDmode, const0_rtx); + lra_invalidate_insn_data (curr_insn); + return true; + } + + /* If the best alternative is with operands 1 and 2 swapped, swap + them. Update the operand numbers of any reloads already + pushed. */ + + if (goal_alt_swapped) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Commutative operand exchange in insn %u\n", + INSN_UID (curr_insn)); + + /* Swap the duplicates too. */ + swap_operands (commutative); + change_p = true; + } + +#ifdef SECONDARY_MEMORY_NEEDED + /* Some target macros SECONDARY_MEMORY_NEEDED (e.g. x86) are defined + too conservatively. So we use the secondary memory only if there + is no any alternative without reloads. */ + use_sec_mem_p = false; + if (! alt_p) + use_sec_mem_p = true; + else if (sec_mem_p) + { + for (i = 0; i < n_operands; i++) + if (! goal_alt_win[i] && ! goal_alt_match_win[i]) + break; + use_sec_mem_p = i < n_operands; + } + + if (use_sec_mem_p) + { + rtx new_reg, set, src, dest; + enum machine_mode sec_mode; + + lra_assert (sec_mem_p); + set = single_set (curr_insn); + lra_assert (set != NULL_RTX && ! side_effects_p (set)); + dest = SET_DEST (set); + src = SET_SRC (set); +#ifdef SECONDARY_MEMORY_NEEDED_MODE + sec_mode = SECONDARY_MEMORY_NEEDED_MODE (GET_MODE (src)); +#else + sec_mode = GET_MODE (src); +#endif + new_reg = lra_create_new_reg (sec_mode, NULL_RTX, + NO_REGS, "secondary"); + /* If the mode is changed, it should be wider. */ + lra_assert (GET_MODE_SIZE (GET_MODE (new_reg)) + >= GET_MODE_SIZE (GET_MODE (src))); + after = emit_spill_move (false, new_reg, dest); + lra_process_new_insns (curr_insn, NULL_RTX, after, + "Inserting the sec. move"); + before = emit_spill_move (true, new_reg, src); + lra_process_new_insns (curr_insn, before, NULL_RTX, "Changing on"); + lra_set_insn_deleted (curr_insn); + return true; + } +#endif + + lra_assert (goal_alt_number >= 0); + lra_set_used_insn_alternative (curr_insn, goal_alt_number); + + if (lra_dump_file != NULL) + { + const char *p; + + fprintf (lra_dump_file, " Choosing alt %d in insn %u:", + goal_alt_number, INSN_UID (curr_insn)); + for (i = 0; i < n_operands; i++) + { + p = (curr_static_id->operand_alternative + [goal_alt_number * n_operands + i].constraint); + if (*p == '\0') + continue; + fprintf (lra_dump_file, " (%d) ", i); + for (; *p != '\0' && *p != ',' && *p != '#'; p++) + fputc (*p, lra_dump_file); + } + fprintf (lra_dump_file, "\n"); + } + + /* Right now, for any pair of operands I and J that are required to + match, with J < I, goal_alt_matches[I] is J. Add I to + goal_alt_matched[J]. */ + + for (i = 0; i < n_operands; i++) + if ((j = goal_alt_matches[i]) >= 0) + { + for (k = 0; goal_alt_matched[j][k] >= 0; k++) + ; + /* We allow matching one output operand and several input + operands. */ + lra_assert (k == 0 + || (curr_static_id->operand[j].type == OP_OUT + && curr_static_id->operand[i].type == OP_IN + && (curr_static_id->operand + [goal_alt_matched[j][0]].type == OP_IN))); + goal_alt_matched[j][k] = i; + goal_alt_matched[j][k + 1] = -1; + } + + for (i = 0; i < n_operands; i++) + goal_alt_win[i] |= goal_alt_match_win[i]; + + /* Any constants that aren't allowed and can't be reloaded into + registers are here changed into memory references. */ + for (i = 0; i < n_operands; i++) + if (goal_alt_win[i]) + { + int regno; + enum reg_class new_class; + rtx reg = *curr_id->operand_loc[i]; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + + if (REG_P (reg) && (regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER) + { + bool ok_p = in_class_p (reg, goal_alt[i], &new_class); + + if (new_class != NO_REGS && get_reg_class (regno) != new_class) + { + lra_assert (ok_p); + change_class (regno, new_class, " Change", true); + } + } + } + else + { + const char *constraint; + char c; + rtx op = *curr_id->operand_loc[i]; + rtx subreg = NULL_RTX; + enum machine_mode mode = curr_operand_mode[i]; + + if (GET_CODE (op) == SUBREG) + { + subreg = op; + op = SUBREG_REG (op); + mode = GET_MODE (op); + } + + if (CONST_POOL_OK_P (mode, op) + && ((targetm.preferred_reload_class + (op, (enum reg_class) goal_alt[i]) == NO_REGS) + || no_input_reloads_p)) + { + rtx tem = force_const_mem (mode, op); + + change_p = true; + if (subreg != NULL_RTX) + tem = gen_rtx_SUBREG (mode, tem, SUBREG_BYTE (subreg)); + + *curr_id->operand_loc[i] = tem; + lra_update_dup (curr_id, i); + process_address (i, &before, &after); + + /* If the alternative accepts constant pool refs directly + there will be no reload needed at all. */ + if (subreg != NULL_RTX) + continue; + /* Skip alternatives before the one requested. */ + constraint = (curr_static_id->operand_alternative + [goal_alt_number * n_operands + i].constraint); + for (; + (c = *constraint) && c != ',' && c != '#'; + constraint += CONSTRAINT_LEN (c, constraint)) + { + if (c == TARGET_MEM_CONSTRAINT || c == 'o') + break; +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_MEMORY_CONSTRAINT (c, constraint) + && EXTRA_CONSTRAINT_STR (tem, c, constraint)) + break; +#endif + } + if (c == '\0' || c == ',' || c == '#') + continue; + + goal_alt_win[i] = true; + } + } + + for (i = 0; i < n_operands; i++) + { + rtx old, new_reg; + rtx op = *curr_id->operand_loc[i]; + + if (goal_alt_win[i]) + { + if (goal_alt[i] == NO_REGS + && REG_P (op) + /* When we assign NO_REGS it means that we will not + assign a hard register to the scratch pseudo by + assigment pass and the scratch pseudo will be + spilled. Spilled scratch pseudos are transformed + back to scratches at the LRA end. */ + && lra_former_scratch_operand_p (curr_insn, i)) + change_class (REGNO (op), NO_REGS, " Change", true); + continue; + } + + /* Operands that match previous ones have already been handled. */ + if (goal_alt_matches[i] >= 0) + continue; + + /* We should not have an operand with a non-offsettable address + appearing where an offsettable address will do. It also may + be a case when the address should be special in other words + not a general one (e.g. it needs no index reg). */ + if (goal_alt_matched[i][0] == -1 && goal_alt_offmemok[i] && MEM_P (op)) + { + enum reg_class rclass; + rtx *loc = &XEXP (op, 0); + enum rtx_code code = GET_CODE (*loc); + + push_to_sequence (before); + rclass = base_reg_class (GET_MODE (op), MEM_ADDR_SPACE (op), + MEM, SCRATCH); + if (GET_RTX_CLASS (code) == RTX_AUTOINC) + new_reg = emit_inc (rclass, *loc, *loc, + /* This value does not matter for MODIFY. */ + GET_MODE_SIZE (GET_MODE (op))); + else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, + "offsetable address", &new_reg)) + lra_emit_move (new_reg, *loc); + before = get_insns (); + end_sequence (); + *loc = new_reg; + lra_update_dup (curr_id, i); + } + else if (goal_alt_matched[i][0] == -1) + { + enum machine_mode mode; + rtx reg, *loc; + int hard_regno, byte; + enum op_type type = curr_static_id->operand[i].type; + + loc = curr_id->operand_loc[i]; + mode = curr_operand_mode[i]; + if (GET_CODE (*loc) == SUBREG) + { + reg = SUBREG_REG (*loc); + byte = SUBREG_BYTE (*loc); + if (REG_P (reg) + /* Strict_low_part requires reload the register not + the sub-register. */ + && (curr_static_id->operand[i].strict_low + || (GET_MODE_SIZE (mode) + <= GET_MODE_SIZE (GET_MODE (reg)) + && (hard_regno + = get_try_hard_regno (REGNO (reg))) >= 0 + && (simplify_subreg_regno + (hard_regno, + GET_MODE (reg), byte, mode) < 0) + && (goal_alt[i] == NO_REGS + || (simplify_subreg_regno + (ira_class_hard_regs[goal_alt[i]][0], + GET_MODE (reg), byte, mode) >= 0))))) + { + loc = &SUBREG_REG (*loc); + mode = GET_MODE (*loc); + } + } + old = *loc; + if (get_reload_reg (type, mode, old, goal_alt[i], "", &new_reg) + && type != OP_OUT) + { + push_to_sequence (before); + lra_emit_move (new_reg, old); + before = get_insns (); + end_sequence (); + } + *loc = new_reg; + if (type != OP_IN + && find_reg_note (curr_insn, REG_UNUSED, old) == NULL_RTX) + { + start_sequence (); + lra_emit_move (type == OP_INOUT ? copy_rtx (old) : old, new_reg); + emit_insn (after); + after = get_insns (); + end_sequence (); + *loc = new_reg; + } + for (j = 0; j < goal_alt_dont_inherit_ops_num; j++) + if (goal_alt_dont_inherit_ops[j] == i) + { + lra_set_regno_unique_value (REGNO (new_reg)); + break; + } + lra_update_dup (curr_id, i); + } + else if (curr_static_id->operand[i].type == OP_IN + && (curr_static_id->operand[goal_alt_matched[i][0]].type + == OP_OUT)) + { + signed char arr[2]; + + arr[0] = i; + arr[1] = -1; + match_reload (goal_alt_matched[i][0], arr, + goal_alt[i], &before, &after); + } + else if (curr_static_id->operand[i].type == OP_OUT + && (curr_static_id->operand[goal_alt_matched[i][0]].type + == OP_IN)) + match_reload (i, goal_alt_matched[i], goal_alt[i], &before, &after); + else + /* We must generate code in any case when function + process_alt_operands decides that it is possible. */ + gcc_unreachable (); + } + if (before != NULL_RTX || after != NULL_RTX + || max_regno_before != max_reg_num ()) + change_p = true; + if (change_p) + { + lra_update_operator_dups (curr_id); + /* Something changes -- process the insn. */ + lra_update_insn_regno_info (curr_insn); + } + lra_process_new_insns (curr_insn, before, after, "Inserting insn reload"); + return change_p; +} + +/* Return true if X is in LIST. */ +static bool +in_list_p (rtx x, rtx list) +{ + for (; list != NULL_RTX; list = XEXP (list, 1)) + if (XEXP (list, 0) == x) + return true; + return false; +} + +/* Return true if X contains an allocatable hard register (if + HARD_REG_P) or a (spilled if SPILLED_P) pseudo. */ +static bool +contains_reg_p (rtx x, bool hard_reg_p, bool spilled_p) +{ + int i, j; + const char *fmt; + enum rtx_code code; + + code = GET_CODE (x); + if (REG_P (x)) + { + int regno = REGNO (x); + HARD_REG_SET alloc_regs; + + if (hard_reg_p) + { + if (regno >= FIRST_PSEUDO_REGISTER) + regno = lra_get_regno_hard_regno (regno); + if (regno < 0) + return false; + COMPL_HARD_REG_SET (alloc_regs, lra_no_alloc_regs); + return overlaps_hard_reg_set_p (alloc_regs, GET_MODE (x), regno); + } + else + { + if (regno < FIRST_PSEUDO_REGISTER) + return false; + if (! spilled_p) + return true; + return lra_get_regno_hard_regno (regno) < 0; + } + } + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (contains_reg_p (XEXP (x, i), hard_reg_p, spilled_p)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (contains_reg_p (XVECEXP (x, i, j), hard_reg_p, spilled_p)) + return true; + } + } + return false; +} + +/* Process all regs in debug location *LOC and change them on + equivalent substitution. Return true if any change was done. */ +static bool +debug_loc_equivalence_change_p (rtx *loc) +{ + rtx subst, reg, x = *loc; + bool result = false; + enum rtx_code code = GET_CODE (x); + const char *fmt; + int i, j; + + if (code == SUBREG) + { + reg = SUBREG_REG (x); + if ((subst = get_equiv_substitution (reg)) != reg + && GET_MODE (subst) == VOIDmode) + { + /* We cannot reload debug location. Simplify subreg here + while we know the inner mode. */ + *loc = simplify_gen_subreg (GET_MODE (x), subst, + GET_MODE (reg), SUBREG_BYTE (x)); + return true; + } + } + if (code == REG && (subst = get_equiv_substitution (x)) != x) + { + *loc = subst; + return true; + } + + /* Scan all the operand sub-expressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + result = debug_loc_equivalence_change_p (&XEXP (x, i)) || result; + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + result + = debug_loc_equivalence_change_p (&XVECEXP (x, i, j)) || result; + } + return result; +} + +/* Maximum allowed number of constraint pass iterations after the last + spill pass. It is for preventing LRA cycling in a bug case. */ +#define MAX_CONSTRAINT_ITERATION_NUMBER 15 + +/* Maximum number of generated reload insns per an insn. It is for + preventing this pass cycling in a bug case. */ +#define MAX_RELOAD_INSNS_NUMBER LRA_MAX_INSN_RELOADS + +/* The current iteration number of this LRA pass. */ +int lra_constraint_iter; + +/* The current iteration number of this LRA pass after the last spill + pass. */ +int lra_constraint_iter_after_spill; + +/* True if we substituted equiv which needs checking register + allocation correctness because the equivalent value contains + allocatable hard registers or when we restore multi-register + pseudo. */ +bool lra_risky_transformations_p; + +/* Return true if REGNO is referenced in more than one block. */ +static bool +multi_block_pseudo_p (int regno) +{ + basic_block bb = NULL; + unsigned int uid; + bitmap_iterator bi; + + if (regno < FIRST_PSEUDO_REGISTER) + return false; + + EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi) + if (bb == NULL) + bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn); + else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb) + return true; + return false; +} + +/* Return true if X contains a pseudo dying in INSN. */ +static bool +dead_pseudo_p (rtx x, rtx insn) +{ + int i, j; + const char *fmt; + enum rtx_code code; + + if (REG_P (x)) + return (insn != NULL_RTX + && find_regno_note (insn, REG_DEAD, REGNO (x)) != NULL_RTX); + code = GET_CODE (x); + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (dead_pseudo_p (XEXP (x, i), insn)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (dead_pseudo_p (XVECEXP (x, i, j), insn)) + return true; + } + } + return false; +} + +/* Return true if INSN contains a dying pseudo in INSN right hand + side. */ +static bool +insn_rhs_dead_pseudo_p (rtx insn) +{ + rtx set = single_set (insn); + + gcc_assert (set != NULL); + return dead_pseudo_p (SET_SRC (set), insn); +} + +/* Return true if any init insn of REGNO contains a dying pseudo in + insn right hand side. */ +static bool +init_insn_rhs_dead_pseudo_p (int regno) +{ + rtx insns = ira_reg_equiv[regno].init_insns; + + if (insns == NULL) + return false; + if (INSN_P (insns)) + return insn_rhs_dead_pseudo_p (insns); + for (; insns != NULL_RTX; insns = XEXP (insns, 1)) + if (insn_rhs_dead_pseudo_p (XEXP (insns, 0))) + return true; + return false; +} + +/* Entry function of LRA constraint pass. Return true if the + constraint pass did change the code. */ +bool +lra_constraints (bool first_p) +{ + bool changed_p; + int i, hard_regno, new_insns_num; + unsigned int min_len, new_min_len; + rtx set, x, dest_reg; + basic_block last_bb; + + lra_constraint_iter++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n********** Local #%d: **********\n\n", + lra_constraint_iter); + lra_constraint_iter_after_spill++; + if (lra_constraint_iter_after_spill > MAX_CONSTRAINT_ITERATION_NUMBER) + internal_error + ("Maximum number of LRA constraint passes is achieved (%d)\n", + MAX_CONSTRAINT_ITERATION_NUMBER); + changed_p = false; + lra_risky_transformations_p = false; + new_insn_uid_start = get_max_uid (); + new_regno_start = first_p ? lra_constraint_new_regno_start : max_reg_num (); + for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++) + if (lra_reg_info[i].nrefs != 0) + { + ira_reg_equiv[i].profitable_p = true; + if ((hard_regno = lra_get_regno_hard_regno (i)) >= 0) + { + int j, nregs = hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (i)]; + + for (j = 0; j < nregs; j++) + df_set_regs_ever_live (hard_regno + j, true); + } + else if ((x = get_equiv_substitution (regno_reg_rtx[i])) != NULL_RTX) + { + bool pseudo_p = contains_reg_p (x, false, false); + rtx set, insn; + + /* We don't use DF for compilation speed sake. So it is + problematic to update live info when we use an + equivalence containing pseudos in more than one BB. */ + if ((pseudo_p && multi_block_pseudo_p (i)) + /* If it is not a reverse equivalence, we check that a + pseudo in rhs of the init insn is not dying in the + insn. Otherwise, the live info at the beginning of + the corresponding BB might be wrong after we + removed the insn. When the equiv can be a + constant, the right hand side of the init insn can + be a pseudo. */ + || (! ((insn = ira_reg_equiv[i].init_insns) != NULL_RTX + && INSN_P (insn) + && (set = single_set (insn)) != NULL_RTX + && REG_P (SET_DEST (set)) + && (int) REGNO (SET_DEST (set)) == i) + && init_insn_rhs_dead_pseudo_p (i))) + ira_reg_equiv[i].defined_p = false; + else if (! first_p && pseudo_p) + /* After RTL transformation, we can not guarantee that + pseudo in the substitution was not reloaded which + might make equivalence invalid. For example, in + reverse equiv of p0 + + p0 <- ... + ... + equiv_mem <- p0 + + the memory address register was reloaded before the + 2nd insn. */ + ira_reg_equiv[i].defined_p = false; + if (contains_reg_p (x, false, true)) + ira_reg_equiv[i].profitable_p = false; + } + } + lra_eliminate (false); + min_len = lra_insn_stack_length (); + new_insns_num = 0; + last_bb = NULL; + changed_p = false; + while ((new_min_len = lra_insn_stack_length ()) != 0) + { + curr_insn = lra_pop_insn (); + --new_min_len; + curr_bb = BLOCK_FOR_INSN (curr_insn); + if (curr_bb != last_bb) + { + last_bb = curr_bb; + bb_reload_num = lra_curr_reload_num; + } + if (min_len > new_min_len) + { + min_len = new_min_len; + new_insns_num = 0; + } + if (new_insns_num > MAX_RELOAD_INSNS_NUMBER) + internal_error + ("Max. number of generated reload insns per insn is achieved (%d)\n", + MAX_RELOAD_INSNS_NUMBER); + new_insns_num++; + if (DEBUG_INSN_P (curr_insn)) + { + /* We need to check equivalence in debug insn and change + pseudo to the equivalent value if necessary. */ + curr_id = lra_get_insn_recog_data (curr_insn); + if (debug_loc_equivalence_change_p (curr_id->operand_loc[0])) + changed_p = true; + } + else if (INSN_P (curr_insn)) + { + if ((set = single_set (curr_insn)) != NULL_RTX) + { + dest_reg = SET_DEST (set); + /* The equivalence pseudo could be set up as SUBREG in a + case when it is a call restore insn in a mode + different from the pseudo mode. */ + if (GET_CODE (dest_reg) == SUBREG) + dest_reg = SUBREG_REG (dest_reg); + if ((REG_P (dest_reg) + && (x = get_equiv_substitution (dest_reg)) != dest_reg + /* Remove insns which set up a pseudo whose value + can not be changed. Such insns might be not in + init_insns because we don't update equiv data + during insn transformations. + + As an example, let suppose that a pseudo got + hard register and on the 1st pass was not + changed to equivalent constant. We generate an + additional insn setting up the pseudo because of + secondary memory movement. Then the pseudo is + spilled and we use the equiv constant. In this + case we should remove the additional insn and + this insn is not init_insns list. */ + && (! MEM_P (x) || MEM_READONLY_P (x) + || in_list_p (curr_insn, + ira_reg_equiv + [REGNO (dest_reg)].init_insns))) + || (((x = get_equiv_substitution (SET_SRC (set))) + != SET_SRC (set)) + && in_list_p (curr_insn, + ira_reg_equiv + [REGNO (SET_SRC (set))].init_insns))) + { + /* This is equiv init insn of pseudo which did not get a + hard register -- remove the insn. */ + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Removing equiv init insn %i (freq=%d)\n", + INSN_UID (curr_insn), + BLOCK_FOR_INSN (curr_insn)->frequency); + debug_rtl_slim (lra_dump_file, + curr_insn, curr_insn, -1, 0); + } + if (contains_reg_p (x, true, false)) + lra_risky_transformations_p = true; + lra_set_insn_deleted (curr_insn); + continue; + } + } + curr_id = lra_get_insn_recog_data (curr_insn); + curr_static_id = curr_id->insn_static_data; + init_curr_insn_input_reloads (); + init_curr_operand_mode (); + if (curr_insn_transform ()) + changed_p = true; + } + } + /* If we used a new hard regno, changed_p should be true because the + hard reg is assigned to a new pseudo. */ +#ifdef ENABLE_CHECKING + if (! changed_p) + { + for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++) + if (lra_reg_info[i].nrefs != 0 + && (hard_regno = lra_get_regno_hard_regno (i)) >= 0) + { + int j, nregs = hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (i)]; + + for (j = 0; j < nregs; j++) + lra_assert (df_regs_ever_live_p (hard_regno + j)); + } + } +#endif + return changed_p; +} + +/* Initiate the LRA constraint pass. It is done once per + function. */ +void +lra_constraints_init (void) +{ +} + +/* Finalize the LRA constraint pass. It is done once per + function. */ +void +lra_constraints_finish (void) +{ +} + + + +/* This page contains code to do inheritance/split + transformations. */ + +/* Number of reloads passed so far in current EBB. */ +static int reloads_num; + +/* Number of calls passed so far in current EBB. */ +static int calls_num; + +/* Current reload pseudo check for validity of elements in + USAGE_INSNS. */ +static int curr_usage_insns_check; + +/* Info about last usage of registers in EBB to do inheritance/split + transformation. Inheritance transformation is done from a spilled + pseudo and split transformations from a hard register or a pseudo + assigned to a hard register. */ +struct usage_insns +{ + /* If the value is equal to CURR_USAGE_INSNS_CHECK, then the member + value INSNS is valid. The insns is chain of optional debug insns + and a finishing non-debug insn using the corresponding reg. */ + int check; + /* Value of global reloads_num at the last insn in INSNS. */ + int reloads_num; + /* Value of global reloads_nums at the last insn in INSNS. */ + int calls_num; + /* It can be true only for splitting. And it means that the restore + insn should be put after insn given by the following member. */ + bool after_p; + /* Next insns in the current EBB which use the original reg and the + original reg value is not changed between the current insn and + the next insns. In order words, e.g. for inheritance, if we need + to use the original reg value again in the next insns we can try + to use the value in a hard register from a reload insn of the + current insn. */ + rtx insns; +}; + +/* Map: regno -> corresponding pseudo usage insns. */ +static struct usage_insns *usage_insns; + +static void +setup_next_usage_insn (int regno, rtx insn, int reloads_num, bool after_p) +{ + usage_insns[regno].check = curr_usage_insns_check; + usage_insns[regno].insns = insn; + usage_insns[regno].reloads_num = reloads_num; + usage_insns[regno].calls_num = calls_num; + usage_insns[regno].after_p = after_p; +} + +/* The function is used to form list REGNO usages which consists of + optional debug insns finished by a non-debug insn using REGNO. + RELOADS_NUM is current number of reload insns processed so far. */ +static void +add_next_usage_insn (int regno, rtx insn, int reloads_num) +{ + rtx next_usage_insns; + + if (usage_insns[regno].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[regno].insns) != NULL_RTX + && DEBUG_INSN_P (insn)) + { + /* Check that we did not add the debug insn yet. */ + if (next_usage_insns != insn + && (GET_CODE (next_usage_insns) != INSN_LIST + || XEXP (next_usage_insns, 0) != insn)) + usage_insns[regno].insns = gen_rtx_INSN_LIST (VOIDmode, insn, + next_usage_insns); + } + else if (NONDEBUG_INSN_P (insn)) + setup_next_usage_insn (regno, insn, reloads_num, false); + else + usage_insns[regno].check = 0; +} + +/* Replace all references to register OLD_REGNO in *LOC with pseudo + register NEW_REG. Return true if any change was made. */ +static bool +substitute_pseudo (rtx *loc, int old_regno, rtx new_reg) +{ + rtx x = *loc; + bool result = false; + enum rtx_code code; + const char *fmt; + int i, j; + + if (x == NULL_RTX) + return false; + + code = GET_CODE (x); + if (code == REG && (int) REGNO (x) == old_regno) + { + enum machine_mode mode = GET_MODE (*loc); + enum machine_mode inner_mode = GET_MODE (new_reg); + + if (mode != inner_mode) + { + if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (inner_mode) + || ! SCALAR_INT_MODE_P (inner_mode)) + new_reg = gen_rtx_SUBREG (mode, new_reg, 0); + else + new_reg = gen_lowpart_SUBREG (mode, new_reg); + } + *loc = new_reg; + return true; + } + + /* Scan all the operand sub-expressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (substitute_pseudo (&XEXP (x, i), old_regno, new_reg)) + result = true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (substitute_pseudo (&XVECEXP (x, i, j), old_regno, new_reg)) + result = true; + } + } + return result; +} + +/* Registers involved in inheritance/split in the current EBB + (inheritance/split pseudos and original registers). */ +static bitmap_head check_only_regs; + +/* Do inheritance transformations for insn INSN, which defines (if + DEF_P) or uses ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which + instruction in the EBB next uses ORIGINAL_REGNO; it has the same + form as the "insns" field of usage_insns. Return true if we + succeed in such transformation. + + The transformations look like: + + p <- ... i <- ... + ... p <- i (new insn) + ... => + <- ... p ... <- ... i ... + or + ... i <- p (new insn) + <- ... p ... <- ... i ... + ... => + <- ... p ... <- ... i ... + where p is a spilled original pseudo and i is a new inheritance pseudo. + + + The inheritance pseudo has the smallest class of two classes CL and + class of ORIGINAL REGNO. */ +static bool +inherit_reload_reg (bool def_p, int original_regno, + enum reg_class cl, rtx insn, rtx next_usage_insns) +{ + enum reg_class rclass = lra_get_allocno_class (original_regno); + rtx original_reg = regno_reg_rtx[original_regno]; + rtx new_reg, new_insns, usage_insn; + + lra_assert (! usage_insns[original_regno].after_p); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + if (! ira_reg_classes_intersect_p[cl][rclass]) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting inheritance for %d " + "because of disjoint classes %s and %s\n", + original_regno, reg_class_names[cl], + reg_class_names[rclass]); + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + return false; + } + if ((ira_class_subset_p[cl][rclass] && cl != rclass) + /* We don't use a subset of two classes because it can be + NO_REGS. This transformation is still profitable in most + cases even if the classes are not intersected as register + move is probably cheaper than a memory load. */ + || ira_class_hard_regs_num[cl] < ira_class_hard_regs_num[rclass]) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Use smallest class of %s and %s\n", + reg_class_names[cl], reg_class_names[rclass]); + + rclass = cl; + } + new_reg = lra_create_new_reg (GET_MODE (original_reg), original_reg, + rclass, "inheritance"); + start_sequence (); + if (def_p) + emit_move_insn (original_reg, new_reg); + else + emit_move_insn (new_reg, original_reg); + new_insns = get_insns (); + end_sequence (); + if (NEXT_INSN (new_insns) != NULL_RTX) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting inheritance %d->%d " + "as it results in 2 or more insns:\n", + original_regno, REGNO (new_reg)); + debug_rtl_slim (lra_dump_file, new_insns, NULL_RTX, -1, 0); + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + return false; + } + substitute_pseudo (&insn, original_regno, new_reg); + lra_update_insn_regno_info (insn); + if (! def_p) + /* We now have a new usage insn for original regno. */ + setup_next_usage_insn (original_regno, new_insns, reloads_num, false); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Original reg change %d->%d (bb%d):\n", + original_regno, REGNO (new_reg), BLOCK_FOR_INSN (insn)->index); + lra_reg_info[REGNO (new_reg)].restore_regno = original_regno; + bitmap_set_bit (&check_only_regs, REGNO (new_reg)); + bitmap_set_bit (&check_only_regs, original_regno); + bitmap_set_bit (&lra_inheritance_pseudos, REGNO (new_reg)); + if (def_p) + lra_process_new_insns (insn, NULL_RTX, new_insns, + "Add original<-inheritance"); + else + lra_process_new_insns (insn, new_insns, NULL_RTX, + "Add inheritance<-original"); + while (next_usage_insns != NULL_RTX) + { + if (GET_CODE (next_usage_insns) != INSN_LIST) + { + usage_insn = next_usage_insns; + lra_assert (NONDEBUG_INSN_P (usage_insn)); + next_usage_insns = NULL; + } + else + { + usage_insn = XEXP (next_usage_insns, 0); + lra_assert (DEBUG_INSN_P (usage_insn)); + next_usage_insns = XEXP (next_usage_insns, 1); + } + substitute_pseudo (&usage_insn, original_regno, new_reg); + lra_update_insn_regno_info (usage_insn); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Inheritance reuse change %d->%d (bb%d):\n", + original_regno, REGNO (new_reg), + BLOCK_FOR_INSN (usage_insn)->index); + debug_rtl_slim (lra_dump_file, usage_insn, usage_insn, + -1, 0); + } + } + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + return true; +} + +/* Return true if we need a caller save/restore for pseudo REGNO which + was assigned to a hard register. */ +static inline bool +need_for_call_save_p (int regno) +{ + lra_assert (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0); + return (usage_insns[regno].calls_num < calls_num + && (overlaps_hard_reg_set_p + (call_used_reg_set, + PSEUDO_REGNO_MODE (regno), reg_renumber[regno]))); +} + +/* Global registers occuring in the current EBB. */ +static bitmap_head ebb_global_regs; + +/* Return true if we need a split for hard register REGNO or pseudo + REGNO which was assigned to a hard register. + POTENTIAL_RELOAD_HARD_REGS contains hard registers which might be + used for reloads since the EBB end. It is an approximation of the + used hard registers in the split range. The exact value would + require expensive calculations. If we were aggressive with + splitting because of the approximation, the split pseudo will save + the same hard register assignment and will be removed in the undo + pass. We still need the approximation because too aggressive + splitting would result in too inaccurate cost calculation in the + assignment pass because of too many generated moves which will be + probably removed in the undo pass. */ +static inline bool +need_for_split_p (HARD_REG_SET potential_reload_hard_regs, int regno) +{ + int hard_regno = regno < FIRST_PSEUDO_REGISTER ? regno : reg_renumber[regno]; + + lra_assert (hard_regno >= 0); + return ((TEST_HARD_REG_BIT (potential_reload_hard_regs, hard_regno) + /* Don't split eliminable hard registers, otherwise we can + split hard registers like hard frame pointer, which + lives on BB start/end according to DF-infrastructure, + when there is a pseudo assigned to the register and + living in the same BB. */ + && (regno >= FIRST_PSEUDO_REGISTER + || ! TEST_HARD_REG_BIT (eliminable_regset, hard_regno)) + && ! TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno) + /* We need at least 2 reloads to make pseudo splitting + profitable. We should provide hard regno splitting in + any case to solve 1st insn scheduling problem when + moving hard register definition up might result in + impossibility to find hard register for reload pseudo of + small register class. */ + && (usage_insns[regno].reloads_num + + (regno < FIRST_PSEUDO_REGISTER ? 0 : 2) < reloads_num) + && (regno < FIRST_PSEUDO_REGISTER + /* For short living pseudos, spilling + inheritance can + be considered a substitution for splitting. + Therefore we do not splitting for local pseudos. It + decreases also aggressiveness of splitting. The + minimal number of references is chosen taking into + account that for 2 references splitting has no sense + as we can just spill the pseudo. */ + || (regno >= FIRST_PSEUDO_REGISTER + && lra_reg_info[regno].nrefs > 3 + && bitmap_bit_p (&ebb_global_regs, regno)))) + || (regno >= FIRST_PSEUDO_REGISTER && need_for_call_save_p (regno))); +} + +/* Return class for the split pseudo created from original pseudo with + ALLOCNO_CLASS and MODE which got a hard register HARD_REGNO. We + choose subclass of ALLOCNO_CLASS which contains HARD_REGNO and + results in no secondary memory movements. */ +static enum reg_class +choose_split_class (enum reg_class allocno_class, + int hard_regno ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ +#ifndef SECONDARY_MEMORY_NEEDED + return allocno_class; +#else + int i; + enum reg_class cl, best_cl = NO_REGS; + enum reg_class hard_reg_class = REGNO_REG_CLASS (hard_regno); + + if (! SECONDARY_MEMORY_NEEDED (allocno_class, allocno_class, mode) + && TEST_HARD_REG_BIT (reg_class_contents[allocno_class], hard_regno)) + return allocno_class; + for (i = 0; + (cl = reg_class_subclasses[allocno_class][i]) != LIM_REG_CLASSES; + i++) + if (! SECONDARY_MEMORY_NEEDED (cl, hard_reg_class, mode) + && ! SECONDARY_MEMORY_NEEDED (hard_reg_class, cl, mode) + && TEST_HARD_REG_BIT (reg_class_contents[cl], hard_regno) + && (best_cl == NO_REGS + || ira_class_hard_regs_num[best_cl] < ira_class_hard_regs_num[cl])) + best_cl = cl; + return best_cl; +#endif +} + +/* Do split transformations for insn INSN, which defines or uses + ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which instruction in + the EBB next uses ORIGINAL_REGNO; it has the same form as the + "insns" field of usage_insns. + + The transformations look like: + + p <- ... p <- ... + ... s <- p (new insn -- save) + ... => + ... p <- s (new insn -- restore) + <- ... p ... <- ... p ... + or + <- ... p ... <- ... p ... + ... s <- p (new insn -- save) + ... => + ... p <- s (new insn -- restore) + <- ... p ... <- ... p ... + + where p is an original pseudo got a hard register or a hard + register and s is a new split pseudo. The save is put before INSN + if BEFORE_P is true. Return true if we succeed in such + transformation. */ +static bool +split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns) +{ + enum reg_class rclass; + rtx original_reg; + int hard_regno; + rtx new_reg, save, restore, usage_insn; + bool after_p; + bool call_save_p; + + if (original_regno < FIRST_PSEUDO_REGISTER) + { + rclass = ira_allocno_class_translate[REGNO_REG_CLASS (original_regno)]; + hard_regno = original_regno; + call_save_p = false; + } + else + { + hard_regno = reg_renumber[original_regno]; + rclass = lra_get_allocno_class (original_regno); + original_reg = regno_reg_rtx[original_regno]; + call_save_p = need_for_call_save_p (original_regno); + } + original_reg = regno_reg_rtx[original_regno]; + lra_assert (hard_regno >= 0); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " ((((((((((((((((((((((((((((((((((((((((((((((((\n"); + if (call_save_p) + { + enum machine_mode sec_mode; + +#ifdef SECONDARY_MEMORY_NEEDED_MODE + sec_mode = SECONDARY_MEMORY_NEEDED_MODE (GET_MODE (original_reg)); +#else + sec_mode = GET_MODE (original_reg); +#endif + new_reg = lra_create_new_reg (sec_mode, NULL_RTX, + NO_REGS, "save"); + } + else + { + rclass = choose_split_class (rclass, hard_regno, + GET_MODE (original_reg)); + if (rclass == NO_REGS) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting split of %d(%s): " + "no good reg class for %d(%s)\n", + original_regno, + reg_class_names[lra_get_allocno_class (original_regno)], + hard_regno, + reg_class_names[REGNO_REG_CLASS (hard_regno)]); + fprintf + (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + } + return false; + } + new_reg = lra_create_new_reg (GET_MODE (original_reg), original_reg, + rclass, "split"); + reg_renumber[REGNO (new_reg)] = hard_regno; + } + save = emit_spill_move (true, new_reg, original_reg); + if (NEXT_INSN (save) != NULL_RTX) + { + lra_assert (! call_save_p); + if (lra_dump_file != NULL) + { + fprintf + (lra_dump_file, + " Rejecting split %d->%d resulting in > 2 %s save insns:\n", + original_regno, REGNO (new_reg), call_save_p ? "call" : ""); + debug_rtl_slim (lra_dump_file, save, NULL_RTX, -1, 0); + fprintf (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + } + return false; + } + restore = emit_spill_move (false, new_reg, original_reg); + if (NEXT_INSN (restore) != NULL_RTX) + { + lra_assert (! call_save_p); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting split %d->%d " + "resulting in > 2 %s restore insns:\n", + original_regno, REGNO (new_reg), call_save_p ? "call" : ""); + debug_rtl_slim (lra_dump_file, restore, NULL_RTX, -1, 0); + fprintf (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + } + return false; + } + after_p = usage_insns[original_regno].after_p; + lra_reg_info[REGNO (new_reg)].restore_regno = original_regno; + bitmap_set_bit (&check_only_regs, REGNO (new_reg)); + bitmap_set_bit (&check_only_regs, original_regno); + bitmap_set_bit (&lra_split_regs, REGNO (new_reg)); + for (;;) + { + if (GET_CODE (next_usage_insns) != INSN_LIST) + { + usage_insn = next_usage_insns; + break; + } + usage_insn = XEXP (next_usage_insns, 0); + lra_assert (DEBUG_INSN_P (usage_insn)); + next_usage_insns = XEXP (next_usage_insns, 1); + substitute_pseudo (&usage_insn, original_regno, new_reg); + lra_update_insn_regno_info (usage_insn); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Split reuse change %d->%d:\n", + original_regno, REGNO (new_reg)); + debug_rtl_slim (lra_dump_file, usage_insn, usage_insn, + -1, 0); + } + } + lra_assert (NOTE_P (usage_insn) || NONDEBUG_INSN_P (usage_insn)); + lra_assert (usage_insn != insn || (after_p && before_p)); + lra_process_new_insns (usage_insn, after_p ? NULL_RTX : restore, + after_p ? restore : NULL_RTX, + call_save_p + ? "Add reg<-save" : "Add reg<-split"); + lra_process_new_insns (insn, before_p ? save : NULL_RTX, + before_p ? NULL_RTX : save, + call_save_p + ? "Add save<-reg" : "Add split<-reg"); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + return true; +} + +/* Recognize that we need a split transformation for insn INSN, which + defines or uses REGNO in its insn biggest MODE (we use it only if + REGNO is a hard register). POTENTIAL_RELOAD_HARD_REGS contains + hard registers which might be used for reloads since the EBB end. + Put the save before INSN if BEFORE_P is true. MAX_UID is maximla + uid before starting INSN processing. Return true if we succeed in + such transformation. */ +static bool +split_if_necessary (int regno, enum machine_mode mode, + HARD_REG_SET potential_reload_hard_regs, + bool before_p, rtx insn, int max_uid) +{ + bool res = false; + int i, nregs = 1; + rtx next_usage_insns; + + if (regno < FIRST_PSEUDO_REGISTER) + nregs = hard_regno_nregs[regno][mode]; + for (i = 0; i < nregs; i++) + if (usage_insns[regno + i].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[regno + i].insns) != NULL_RTX + /* To avoid processing the register twice or more. */ + && ((GET_CODE (next_usage_insns) != INSN_LIST + && INSN_UID (next_usage_insns) < max_uid) + || (GET_CODE (next_usage_insns) == INSN_LIST + && (INSN_UID (XEXP (next_usage_insns, 0)) < max_uid))) + && need_for_split_p (potential_reload_hard_regs, regno + i) + && split_reg (before_p, regno + i, insn, next_usage_insns)) + res = true; + return res; +} + +/* Check only registers living at the current program point in the + current EBB. */ +static bitmap_head live_regs; + +/* Update live info in EBB given by its HEAD and TAIL insns after + inheritance/split transformation. The function removes dead moves + too. */ +static void +update_ebb_live_info (rtx head, rtx tail) +{ + unsigned int j; + int regno; + bool live_p; + rtx prev_insn, set; + bool remove_p; + basic_block last_bb, prev_bb, curr_bb; + bitmap_iterator bi; + struct lra_insn_reg *reg; + edge e; + edge_iterator ei; + + last_bb = BLOCK_FOR_INSN (tail); + prev_bb = NULL; + for (curr_insn = tail; + curr_insn != PREV_INSN (head); + curr_insn = prev_insn) + { + prev_insn = PREV_INSN (curr_insn); + if (! INSN_P (curr_insn)) + continue; + curr_bb = BLOCK_FOR_INSN (curr_insn); + if (curr_bb != prev_bb) + { + if (prev_bb != NULL) + { + /* Update df_get_live_in (prev_bb): */ + EXECUTE_IF_SET_IN_BITMAP (&check_only_regs, 0, j, bi) + if (bitmap_bit_p (&live_regs, j)) + bitmap_set_bit (df_get_live_in (prev_bb), j); + else + bitmap_clear_bit (df_get_live_in (prev_bb), j); + } + if (curr_bb != last_bb) + { + /* Update df_get_live_out (curr_bb): */ + EXECUTE_IF_SET_IN_BITMAP (&check_only_regs, 0, j, bi) + { + live_p = bitmap_bit_p (&live_regs, j); + if (! live_p) + FOR_EACH_EDGE (e, ei, curr_bb->succs) + if (bitmap_bit_p (df_get_live_in (e->dest), j)) + { + live_p = true; + break; + } + if (live_p) + bitmap_set_bit (df_get_live_out (curr_bb), j); + else + bitmap_clear_bit (df_get_live_out (curr_bb), j); + } + } + prev_bb = curr_bb; + bitmap_and (&live_regs, &check_only_regs, df_get_live_out (curr_bb)); + } + if (DEBUG_INSN_P (curr_insn)) + continue; + curr_id = lra_get_insn_recog_data (curr_insn); + remove_p = false; + if ((set = single_set (curr_insn)) != NULL_RTX && REG_P (SET_DEST (set)) + && (regno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER + && bitmap_bit_p (&check_only_regs, regno) + && ! bitmap_bit_p (&live_regs, regno)) + remove_p = true; + /* See which defined values die here. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && ! reg->subreg_p) + bitmap_clear_bit (&live_regs, reg->regno); + /* Mark each used value as live. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type == OP_IN + && bitmap_bit_p (&check_only_regs, reg->regno)) + bitmap_set_bit (&live_regs, reg->regno); + /* It is quite important to remove dead move insns because it + means removing dead store. We don't need to process them for + constraints. */ + if (remove_p) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Removing dead insn:\n "); + debug_rtl_slim (lra_dump_file, curr_insn, curr_insn, -1, 0); + } + lra_set_insn_deleted (curr_insn); + } + } +} + +/* The structure describes info to do an inheritance for the current + insn. We need to collect such info first before doing the + transformations because the transformations change the insn + internal representation. */ +struct to_inherit +{ + /* Original regno. */ + int regno; + /* Subsequent insns which can inherit original reg value. */ + rtx insns; +}; + +/* Array containing all info for doing inheritance from the current + insn. */ +static struct to_inherit to_inherit[LRA_MAX_INSN_RELOADS]; + +/* Number elements in the previous array. */ +static int to_inherit_num; + +/* Add inheritance info REGNO and INSNS. Their meaning is described in + structure to_inherit. */ +static void +add_to_inherit (int regno, rtx insns) +{ + int i; + + for (i = 0; i < to_inherit_num; i++) + if (to_inherit[i].regno == regno) + return; + lra_assert (to_inherit_num < LRA_MAX_INSN_RELOADS); + to_inherit[to_inherit_num].regno = regno; + to_inherit[to_inherit_num++].insns = insns; +} + +/* Return the last non-debug insn in basic block BB, or the block begin + note if none. */ +static rtx +get_last_insertion_point (basic_block bb) +{ + rtx insn; + + FOR_BB_INSNS_REVERSE (bb, insn) + if (NONDEBUG_INSN_P (insn) || NOTE_INSN_BASIC_BLOCK_P (insn)) + return insn; + gcc_unreachable (); +} + +/* Set up RES by registers living on edges FROM except the edge (FROM, + TO) or by registers set up in a jump insn in BB FROM. */ +static void +get_live_on_other_edges (basic_block from, basic_block to, bitmap res) +{ + rtx last; + struct lra_insn_reg *reg; + edge e; + edge_iterator ei; + + lra_assert (to != NULL); + bitmap_clear (res); + FOR_EACH_EDGE (e, ei, from->succs) + if (e->dest != to) + bitmap_ior_into (res, df_get_live_in (e->dest)); + last = get_last_insertion_point (from); + if (! JUMP_P (last)) + return; + curr_id = lra_get_insn_recog_data (last); + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type != OP_IN) + bitmap_set_bit (res, reg->regno); +} + +/* Used as a temporary results of some bitmap calculations. */ +static bitmap_head temp_bitmap; + +/* Do inheritance/split transformations in EBB starting with HEAD and + finishing on TAIL. We process EBB insns in the reverse order. + Return true if we did any inheritance/split transformation in the + EBB. + + We should avoid excessive splitting which results in worse code + because of inaccurate cost calculations for spilling new split + pseudos in such case. To achieve this we do splitting only if + register pressure is high in given basic block and there are reload + pseudos requiring hard registers. We could do more register + pressure calculations at any given program point to avoid necessary + splitting even more but it is to expensive and the current approach + works well enough. */ +static bool +inherit_in_ebb (rtx head, rtx tail) +{ + int i, src_regno, dst_regno, nregs; + bool change_p, succ_p; + rtx prev_insn, next_usage_insns, set, last_insn; + enum reg_class cl; + struct lra_insn_reg *reg; + basic_block last_processed_bb, curr_bb = NULL; + HARD_REG_SET potential_reload_hard_regs, live_hard_regs; + bitmap to_process; + unsigned int j; + bitmap_iterator bi; + bool head_p, after_p; + + change_p = false; + curr_usage_insns_check++; + reloads_num = calls_num = 0; + bitmap_clear (&check_only_regs); + last_processed_bb = NULL; + CLEAR_HARD_REG_SET (potential_reload_hard_regs); + CLEAR_HARD_REG_SET (live_hard_regs); + /* We don't process new insns generated in the loop. */ + for (curr_insn = tail; curr_insn != PREV_INSN (head); curr_insn = prev_insn) + { + prev_insn = PREV_INSN (curr_insn); + if (BLOCK_FOR_INSN (curr_insn) != NULL) + curr_bb = BLOCK_FOR_INSN (curr_insn); + if (last_processed_bb != curr_bb) + { + /* We are at the end of BB. Add qualified living + pseudos for potential splitting. */ + to_process = df_get_live_out (curr_bb); + if (last_processed_bb != NULL) + { + /* We are somewhere in the middle of EBB. */ + get_live_on_other_edges (curr_bb, last_processed_bb, + &temp_bitmap); + to_process = &temp_bitmap; + } + last_processed_bb = curr_bb; + last_insn = get_last_insertion_point (curr_bb); + after_p = (! JUMP_P (last_insn) + && (! CALL_P (last_insn) + || (find_reg_note (last_insn, + REG_NORETURN, NULL_RTX) == NULL_RTX + && ! SIBLING_CALL_P (last_insn)))); + REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_out (curr_bb)); + IOR_HARD_REG_SET (live_hard_regs, eliminable_regset); + IOR_HARD_REG_SET (live_hard_regs, lra_no_alloc_regs); + CLEAR_HARD_REG_SET (potential_reload_hard_regs); + EXECUTE_IF_SET_IN_BITMAP (to_process, 0, j, bi) + { + if ((int) j >= lra_constraint_new_regno_start) + break; + if (j < FIRST_PSEUDO_REGISTER || reg_renumber[j] >= 0) + { + if (j < FIRST_PSEUDO_REGISTER) + SET_HARD_REG_BIT (live_hard_regs, j); + else + add_to_hard_reg_set (&live_hard_regs, + PSEUDO_REGNO_MODE (j), + reg_renumber[j]); + setup_next_usage_insn (j, last_insn, reloads_num, after_p); + } + } + } + src_regno = dst_regno = -1; + if (NONDEBUG_INSN_P (curr_insn) + && (set = single_set (curr_insn)) != NULL_RTX + && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))) + { + src_regno = REGNO (SET_SRC (set)); + dst_regno = REGNO (SET_DEST (set)); + } + if (src_regno < lra_constraint_new_regno_start + && src_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[src_regno] < 0 + && dst_regno >= lra_constraint_new_regno_start + && (cl = lra_get_allocno_class (dst_regno)) != NO_REGS) + { + /* 'reload_pseudo <- original_pseudo'. */ + reloads_num++; + succ_p = false; + if (usage_insns[src_regno].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[src_regno].insns) != NULL_RTX) + succ_p = inherit_reload_reg (false, src_regno, cl, + curr_insn, next_usage_insns); + if (succ_p) + change_p = true; + else + setup_next_usage_insn (src_regno, curr_insn, reloads_num, false); + if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs)) + IOR_HARD_REG_SET (potential_reload_hard_regs, + reg_class_contents[cl]); + } + else if (src_regno >= lra_constraint_new_regno_start + && dst_regno < lra_constraint_new_regno_start + && dst_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[dst_regno] < 0 + && (cl = lra_get_allocno_class (src_regno)) != NO_REGS + && usage_insns[dst_regno].check == curr_usage_insns_check + && (next_usage_insns + = usage_insns[dst_regno].insns) != NULL_RTX) + { + reloads_num++; + /* 'original_pseudo <- reload_pseudo'. */ + if (! JUMP_P (curr_insn) + && inherit_reload_reg (true, dst_regno, cl, + curr_insn, next_usage_insns)) + change_p = true; + /* Invalidate. */ + usage_insns[dst_regno].check = 0; + if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs)) + IOR_HARD_REG_SET (potential_reload_hard_regs, + reg_class_contents[cl]); + } + else if (INSN_P (curr_insn)) + { + int max_uid = get_max_uid (); + + curr_id = lra_get_insn_recog_data (curr_insn); + to_inherit_num = 0; + /* Process insn definitions. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type != OP_IN + && (dst_regno = reg->regno) < lra_constraint_new_regno_start) + { + if (dst_regno >= FIRST_PSEUDO_REGISTER && reg->type == OP_OUT + && reg_renumber[dst_regno] < 0 && ! reg->subreg_p + && usage_insns[dst_regno].check == curr_usage_insns_check + && (next_usage_insns + = usage_insns[dst_regno].insns) != NULL_RTX) + { + struct lra_insn_reg *r; + + for (r = curr_id->regs; r != NULL; r = r->next) + if (r->type != OP_OUT && r->regno == dst_regno) + break; + /* Don't do inheritance if the pseudo is also + used in the insn. */ + if (r == NULL) + /* We can not do inheritance right now + because the current insn reg info (chain + regs) can change after that. */ + add_to_inherit (dst_regno, next_usage_insns); + } + /* We can not process one reg twice here because of + usage_insns invalidation. */ + if ((dst_regno < FIRST_PSEUDO_REGISTER + || reg_renumber[dst_regno] >= 0) + && ! reg->subreg_p && reg->type == OP_OUT) + { + HARD_REG_SET s; + + if (split_if_necessary (dst_regno, reg->biggest_mode, + potential_reload_hard_regs, + false, curr_insn, max_uid)) + change_p = true; + CLEAR_HARD_REG_SET (s); + if (dst_regno < FIRST_PSEUDO_REGISTER) + add_to_hard_reg_set (&s, reg->biggest_mode, dst_regno); + else + add_to_hard_reg_set (&s, PSEUDO_REGNO_MODE (dst_regno), + reg_renumber[dst_regno]); + AND_COMPL_HARD_REG_SET (live_hard_regs, s); + } + /* We should invalidate potential inheritance or + splitting for the current insn usages to the next + usage insns (see code below) as the output pseudo + prevents this. */ + if ((dst_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[dst_regno] < 0) + || (reg->type == OP_OUT && ! reg->subreg_p + && (dst_regno < FIRST_PSEUDO_REGISTER + || reg_renumber[dst_regno] >= 0))) + { + /* Invalidate. */ + if (dst_regno >= FIRST_PSEUDO_REGISTER) + usage_insns[dst_regno].check = 0; + else + { + nregs = hard_regno_nregs[dst_regno][reg->biggest_mode]; + for (i = 0; i < nregs; i++) + usage_insns[dst_regno + i].check = 0; + } + } + } + if (! JUMP_P (curr_insn)) + for (i = 0; i < to_inherit_num; i++) + if (inherit_reload_reg (true, to_inherit[i].regno, + ALL_REGS, curr_insn, + to_inherit[i].insns)) + change_p = true; + if (CALL_P (curr_insn)) + { + rtx cheap, pat, dest, restore; + int regno, hard_regno; + + calls_num++; + if ((cheap = find_reg_note (curr_insn, + REG_RETURNED, NULL_RTX)) != NULL_RTX + && ((cheap = XEXP (cheap, 0)), true) + && (regno = REGNO (cheap)) >= FIRST_PSEUDO_REGISTER + && (hard_regno = reg_renumber[regno]) >= 0 + /* If there are pending saves/restores, the + optimization is not worth. */ + && usage_insns[regno].calls_num == calls_num - 1 + && TEST_HARD_REG_BIT (call_used_reg_set, hard_regno)) + { + /* Restore the pseudo from the call result as + REG_RETURNED note says that the pseudo value is + in the call result and the pseudo is an argument + of the call. */ + pat = PATTERN (curr_insn); + if (GET_CODE (pat) == PARALLEL) + pat = XVECEXP (pat, 0, 0); + dest = SET_DEST (pat); + start_sequence (); + emit_move_insn (cheap, copy_rtx (dest)); + restore = get_insns (); + end_sequence (); + lra_process_new_insns (curr_insn, NULL, restore, + "Inserting call parameter restore"); + /* We don't need to save/restore of the pseudo from + this call. */ + usage_insns[regno].calls_num = calls_num; + bitmap_set_bit (&check_only_regs, regno); + } + } + to_inherit_num = 0; + /* Process insn usages. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if ((reg->type != OP_OUT + || (reg->type == OP_OUT && reg->subreg_p)) + && (src_regno = reg->regno) < lra_constraint_new_regno_start) + { + if (src_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[src_regno] < 0 && reg->type == OP_IN) + { + if (usage_insns[src_regno].check == curr_usage_insns_check + && (next_usage_insns + = usage_insns[src_regno].insns) != NULL_RTX + && NONDEBUG_INSN_P (curr_insn)) + add_to_inherit (src_regno, next_usage_insns); + else + /* Add usages. */ + add_next_usage_insn (src_regno, curr_insn, reloads_num); + } + else if (src_regno < FIRST_PSEUDO_REGISTER + || reg_renumber[src_regno] >= 0) + { + bool before_p; + rtx use_insn = curr_insn; + + before_p = (JUMP_P (curr_insn) + || (CALL_P (curr_insn) && reg->type == OP_IN)); + if (NONDEBUG_INSN_P (curr_insn) + && split_if_necessary (src_regno, reg->biggest_mode, + potential_reload_hard_regs, + before_p, curr_insn, max_uid)) + { + if (reg->subreg_p) + lra_risky_transformations_p = true; + change_p = true; + /* Invalidate. */ + usage_insns[src_regno].check = 0; + if (before_p) + use_insn = PREV_INSN (curr_insn); + } + if (NONDEBUG_INSN_P (curr_insn)) + { + if (src_regno < FIRST_PSEUDO_REGISTER) + add_to_hard_reg_set (&live_hard_regs, + reg->biggest_mode, src_regno); + else + add_to_hard_reg_set (&live_hard_regs, + PSEUDO_REGNO_MODE (src_regno), + reg_renumber[src_regno]); + } + add_next_usage_insn (src_regno, use_insn, reloads_num); + } + } + for (i = 0; i < to_inherit_num; i++) + { + src_regno = to_inherit[i].regno; + if (inherit_reload_reg (false, src_regno, ALL_REGS, + curr_insn, to_inherit[i].insns)) + change_p = true; + else + setup_next_usage_insn (src_regno, curr_insn, reloads_num, false); + } + } + /* We reached the start of the current basic block. */ + if (prev_insn == NULL_RTX || prev_insn == PREV_INSN (head) + || BLOCK_FOR_INSN (prev_insn) != curr_bb) + { + /* We reached the beginning of the current block -- do + rest of spliting in the current BB. */ + to_process = df_get_live_in (curr_bb); + if (BLOCK_FOR_INSN (head) != curr_bb) + { + /* We are somewhere in the middle of EBB. */ + get_live_on_other_edges (EDGE_PRED (curr_bb, 0)->src, + curr_bb, &temp_bitmap); + to_process = &temp_bitmap; + } + head_p = true; + EXECUTE_IF_SET_IN_BITMAP (to_process, 0, j, bi) + { + if ((int) j >= lra_constraint_new_regno_start) + break; + if (((int) j < FIRST_PSEUDO_REGISTER || reg_renumber[j] >= 0) + && usage_insns[j].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[j].insns) != NULL_RTX) + { + if (need_for_split_p (potential_reload_hard_regs, j)) + { + if (lra_dump_file != NULL && head_p) + { + fprintf (lra_dump_file, + " ----------------------------------\n"); + head_p = false; + } + if (split_reg (false, j, bb_note (curr_bb), + next_usage_insns)) + change_p = true; + } + usage_insns[j].check = 0; + } + } + } + } + return change_p; +} + +/* This value affects EBB forming. If probability of edge from EBB to + a BB is not greater than the following value, we don't add the BB + to EBB. */ +#define EBB_PROBABILITY_CUTOFF (REG_BR_PROB_BASE / 2) + +/* Current number of inheritance/split iteration. */ +int lra_inheritance_iter; + +/* Entry function for inheritance/split pass. */ +void +lra_inheritance (void) +{ + int i; + basic_block bb, start_bb; + edge e; + + timevar_push (TV_LRA_INHERITANCE); + lra_inheritance_iter++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n********** Inheritance #%d: **********\n\n", + lra_inheritance_iter); + curr_usage_insns_check = 0; + usage_insns = XNEWVEC (struct usage_insns, lra_constraint_new_regno_start); + for (i = 0; i < lra_constraint_new_regno_start; i++) + usage_insns[i].check = 0; + bitmap_initialize (&check_only_regs, ®_obstack); + bitmap_initialize (&live_regs, ®_obstack); + bitmap_initialize (&temp_bitmap, ®_obstack); + bitmap_initialize (&ebb_global_regs, ®_obstack); + FOR_EACH_BB (bb) + { + start_bb = bb; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "EBB"); + /* Form a EBB starting with BB. */ + bitmap_clear (&ebb_global_regs); + bitmap_ior_into (&ebb_global_regs, df_get_live_in (bb)); + for (;;) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " %d", bb->index); + if (bb->next_bb == EXIT_BLOCK_PTR || LABEL_P (BB_HEAD (bb->next_bb))) + break; + e = find_fallthru_edge (bb->succs); + if (! e) + break; + if (e->probability <= EBB_PROBABILITY_CUTOFF) + break; + bb = bb->next_bb; + } + bitmap_ior_into (&ebb_global_regs, df_get_live_out (bb)); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n"); + if (inherit_in_ebb (BB_HEAD (start_bb), BB_END (bb))) + /* Remember that the EBB head and tail can change in + inherit_in_ebb. */ + update_ebb_live_info (BB_HEAD (start_bb), BB_END (bb)); + } + bitmap_clear (&ebb_global_regs); + bitmap_clear (&temp_bitmap); + bitmap_clear (&live_regs); + bitmap_clear (&check_only_regs); + free (usage_insns); + + timevar_pop (TV_LRA_INHERITANCE); +} + + + +/* This page contains code to undo failed inheritance/split + transformations. */ + +/* Current number of iteration undoing inheritance/split. */ +int lra_undo_inheritance_iter; + +/* Fix BB live info LIVE after removing pseudos created on pass doing + inheritance/split which are REMOVED_PSEUDOS. */ +static void +fix_bb_live_info (bitmap live, bitmap removed_pseudos) +{ + unsigned int regno; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (removed_pseudos, 0, regno, bi) + if (bitmap_clear_bit (live, regno)) + bitmap_set_bit (live, lra_reg_info[regno].restore_regno); +} + +/* Return regno of the (subreg of) REG. Otherwise, return a negative + number. */ +static int +get_regno (rtx reg) +{ + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (REG_P (reg)) + return REGNO (reg); + return -1; +} + +/* Remove inheritance/split pseudos which are in REMOVE_PSEUDOS and + return true if we did any change. The undo transformations for + inheritance looks like + i <- i2 + p <- i => p <- i2 + or removing + p <- i, i <- p, and i <- i3 + where p is original pseudo from which inheritance pseudo i was + created, i and i3 are removed inheritance pseudos, i2 is another + not removed inheritance pseudo. All split pseudos or other + occurrences of removed inheritance pseudos are changed on the + corresponding original pseudos. + + The function also schedules insns changed and created during + inheritance/split pass for processing by the subsequent constraint + pass. */ +static bool +remove_inheritance_pseudos (bitmap remove_pseudos) +{ + basic_block bb; + int regno, sregno, prev_sregno, dregno, restore_regno; + rtx set, prev_set, prev_insn; + bool change_p, done_p; + + change_p = ! bitmap_empty_p (remove_pseudos); + /* We can not finish the function right away if CHANGE_P is true + because we need to marks insns affected by previous + inheritance/split pass for processing by the subsequent + constraint pass. */ + FOR_EACH_BB (bb) + { + fix_bb_live_info (df_get_live_in (bb), remove_pseudos); + fix_bb_live_info (df_get_live_out (bb), remove_pseudos); + FOR_BB_INSNS_REVERSE (bb, curr_insn) + { + if (! INSN_P (curr_insn)) + continue; + done_p = false; + sregno = dregno = -1; + if (change_p && NONDEBUG_INSN_P (curr_insn) + && (set = single_set (curr_insn)) != NULL_RTX) + { + dregno = get_regno (SET_DEST (set)); + sregno = get_regno (SET_SRC (set)); + } + + if (sregno >= 0 && dregno >= 0) + { + if ((bitmap_bit_p (remove_pseudos, sregno) + && (lra_reg_info[sregno].restore_regno == dregno + || (bitmap_bit_p (remove_pseudos, dregno) + && (lra_reg_info[sregno].restore_regno + == lra_reg_info[dregno].restore_regno)))) + || (bitmap_bit_p (remove_pseudos, dregno) + && lra_reg_info[dregno].restore_regno == sregno)) + /* One of the following cases: + original <- removed inheritance pseudo + removed inherit pseudo <- another removed inherit pseudo + removed inherit pseudo <- original pseudo + Or + removed_split_pseudo <- original_reg + original_reg <- removed_split_pseudo */ + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Removing %s:\n", + bitmap_bit_p (&lra_split_regs, sregno) + || bitmap_bit_p (&lra_split_regs, dregno) + ? "split" : "inheritance"); + debug_rtl_slim (lra_dump_file, + curr_insn, curr_insn, -1, 0); + } + lra_set_insn_deleted (curr_insn); + done_p = true; + } + else if (bitmap_bit_p (remove_pseudos, sregno) + && bitmap_bit_p (&lra_inheritance_pseudos, sregno)) + { + /* Search the following pattern: + inherit_or_split_pseudo1 <- inherit_or_split_pseudo2 + original_pseudo <- inherit_or_split_pseudo1 + where the 2nd insn is the current insn and + inherit_or_split_pseudo2 is not removed. If it is found, + change the current insn onto: + original_pseudo <- inherit_or_split_pseudo2. */ + for (prev_insn = PREV_INSN (curr_insn); + prev_insn != NULL_RTX && ! NONDEBUG_INSN_P (prev_insn); + prev_insn = PREV_INSN (prev_insn)) + ; + if (prev_insn != NULL_RTX && BLOCK_FOR_INSN (prev_insn) == bb + && (prev_set = single_set (prev_insn)) != NULL_RTX + /* There should be no subregs in insn we are + searching because only the original reg might + be in subreg when we changed the mode of + load/store for splitting. */ + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_SRC (prev_set)) + && (int) REGNO (SET_DEST (prev_set)) == sregno + && ((prev_sregno = REGNO (SET_SRC (prev_set))) + >= FIRST_PSEUDO_REGISTER) + /* As we consider chain of inheritance or + splitting described in above comment we should + check that sregno and prev_sregno were + inheritance/split pseudos created from the + same original regno. */ + && (lra_reg_info[sregno].restore_regno + == lra_reg_info[prev_sregno].restore_regno) + && ! bitmap_bit_p (remove_pseudos, prev_sregno)) + { + lra_assert (GET_MODE (SET_SRC (prev_set)) + == GET_MODE (regno_reg_rtx[sregno])); + if (GET_CODE (SET_SRC (set)) == SUBREG) + SUBREG_REG (SET_SRC (set)) = SET_SRC (prev_set); + else + SET_SRC (set) = SET_SRC (prev_set); + lra_push_insn_and_update_insn_regno_info (curr_insn); + lra_set_used_insn_alternative_by_uid + (INSN_UID (curr_insn), -1); + done_p = true; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Change reload insn:\n"); + debug_rtl_slim (lra_dump_file, + curr_insn, curr_insn, -1, 0); + } + } + } + } + if (! done_p) + { + struct lra_insn_reg *reg; + bool restored_regs_p = false; + bool kept_regs_p = false; + + curr_id = lra_get_insn_recog_data (curr_insn); + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + { + regno = reg->regno; + restore_regno = lra_reg_info[regno].restore_regno; + if (restore_regno >= 0) + { + if (change_p && bitmap_bit_p (remove_pseudos, regno)) + { + substitute_pseudo (&curr_insn, regno, + regno_reg_rtx[restore_regno]); + restored_regs_p = true; + } + else + kept_regs_p = true; + } + } + if (NONDEBUG_INSN_P (curr_insn) && kept_regs_p) + { + /* The instruction has changed since the previous + constraints pass. */ + lra_push_insn_and_update_insn_regno_info (curr_insn); + lra_set_used_insn_alternative_by_uid + (INSN_UID (curr_insn), -1); + } + else if (restored_regs_p) + /* The instruction has been restored to the form that + it had during the previous constraints pass. */ + lra_update_insn_regno_info (curr_insn); + if (restored_regs_p && lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Insn after restoring regs:\n"); + debug_rtl_slim (lra_dump_file, curr_insn, curr_insn, -1, 0); + } + } + } + } + return change_p; +} + +/* Entry function for undoing inheritance/split transformation. Return true + if we did any RTL change in this pass. */ +bool +lra_undo_inheritance (void) +{ + unsigned int regno; + int restore_regno, hard_regno; + int n_all_inherit, n_inherit, n_all_split, n_split; + bitmap_head remove_pseudos; + bitmap_iterator bi; + bool change_p; + + lra_undo_inheritance_iter++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + "\n********** Undoing inheritance #%d: **********\n\n", + lra_undo_inheritance_iter); + bitmap_initialize (&remove_pseudos, ®_obstack); + n_inherit = n_all_inherit = 0; + EXECUTE_IF_SET_IN_BITMAP (&lra_inheritance_pseudos, 0, regno, bi) + if (lra_reg_info[regno].restore_regno >= 0) + { + n_all_inherit++; + if (reg_renumber[regno] < 0) + bitmap_set_bit (&remove_pseudos, regno); + else + n_inherit++; + } + if (lra_dump_file != NULL && n_all_inherit != 0) + fprintf (lra_dump_file, "Inherit %d out of %d (%.2f%%)\n", + n_inherit, n_all_inherit, + (double) n_inherit / n_all_inherit * 100); + n_split = n_all_split = 0; + EXECUTE_IF_SET_IN_BITMAP (&lra_split_regs, 0, regno, bi) + if ((restore_regno = lra_reg_info[regno].restore_regno) >= 0) + { + n_all_split++; + hard_regno = (restore_regno >= FIRST_PSEUDO_REGISTER + ? reg_renumber[restore_regno] : restore_regno); + if (hard_regno < 0 || reg_renumber[regno] == hard_regno) + bitmap_set_bit (&remove_pseudos, regno); + else + { + n_split++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Keep split r%d (orig=r%d)\n", + regno, restore_regno); + } + } + if (lra_dump_file != NULL && n_all_split != 0) + fprintf (lra_dump_file, "Split %d out of %d (%.2f%%)\n", + n_split, n_all_split, + (double) n_split / n_all_split * 100); + change_p = remove_inheritance_pseudos (&remove_pseudos); + bitmap_clear (&remove_pseudos); + /* Clear restore_regnos. */ + EXECUTE_IF_SET_IN_BITMAP (&lra_inheritance_pseudos, 0, regno, bi) + lra_reg_info[regno].restore_regno = -1; + EXECUTE_IF_SET_IN_BITMAP (&lra_split_regs, 0, regno, bi) + lra_reg_info[regno].restore_regno = -1; + return change_p; +} |