| /* Optimize by combining instructions for GNU compiler. |
| Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
| 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 2, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING. If not, write to the Free |
| Software Foundation, 59 Temple Place - Suite 330, Boston, MA |
| 02111-1307, USA. */ |
| |
| /* This module is essentially the "combiner" phase of the U. of Arizona |
| Portable Optimizer, but redone to work on our list-structured |
| representation for RTL instead of their string representation. |
| |
| The LOG_LINKS of each insn identify the most recent assignment |
| to each REG used in the insn. It is a list of previous insns, |
| each of which contains a SET for a REG that is used in this insn |
| and not used or set in between. LOG_LINKs never cross basic blocks. |
| They were set up by the preceding pass (lifetime analysis). |
| |
| We try to combine each pair of insns joined by a logical link. |
| We also try to combine triples of insns A, B and C when |
| C has a link back to B and B has a link back to A. |
| |
| LOG_LINKS does not have links for use of the CC0. They don't |
| need to, because the insn that sets the CC0 is always immediately |
| before the insn that tests it. So we always regard a branch |
| insn as having a logical link to the preceding insn. The same is true |
| for an insn explicitly using CC0. |
| |
| We check (with use_crosses_set_p) to avoid combining in such a way |
| as to move a computation to a place where its value would be different. |
| |
| Combination is done by mathematically substituting the previous |
| insn(s) values for the regs they set into the expressions in |
| the later insns that refer to these regs. If the result is a valid insn |
| for our target machine, according to the machine description, |
| we install it, delete the earlier insns, and update the data flow |
| information (LOG_LINKS and REG_NOTES) for what we did. |
| |
| There are a few exceptions where the dataflow information created by |
| flow.c aren't completely updated: |
| |
| - reg_live_length is not updated |
| - a LOG_LINKS entry that refers to an insn with multiple SETs may be |
| removed because there is no way to know which register it was |
| linking |
| |
| To simplify substitution, we combine only when the earlier insn(s) |
| consist of only a single assignment. To simplify updating afterward, |
| we never combine when a subroutine call appears in the middle. |
| |
| Since we do not represent assignments to CC0 explicitly except when that |
| is all an insn does, there is no LOG_LINKS entry in an insn that uses |
| the condition code for the insn that set the condition code. |
| Fortunately, these two insns must be consecutive. |
| Therefore, every JUMP_INSN is taken to have an implicit logical link |
| to the preceding insn. This is not quite right, since non-jumps can |
| also use the condition code; but in practice such insns would not |
| combine anyway. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "rtl.h" |
| #include "tree.h" |
| #include "tm_p.h" |
| #include "flags.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "basic-block.h" |
| #include "insn-config.h" |
| #include "function.h" |
| /* Include expr.h after insn-config.h so we get HAVE_conditional_move. */ |
| #include "expr.h" |
| #include "insn-attr.h" |
| #include "recog.h" |
| #include "real.h" |
| #include "toplev.h" |
| #include "target.h" |
| #include "optabs.h" |
| #include "insn-codes.h" |
| #include "rtlhooks-def.h" |
| /* Include output.h for dump_file. */ |
| #include "output.h" |
| #include "params.h" |
| |
| /* Number of attempts to combine instructions in this function. */ |
| |
| static int combine_attempts; |
| |
| /* Number of attempts that got as far as substitution in this function. */ |
| |
| static int combine_merges; |
| |
| /* Number of instructions combined with added SETs in this function. */ |
| |
| static int combine_extras; |
| |
| /* Number of instructions combined in this function. */ |
| |
| static int combine_successes; |
| |
| /* Totals over entire compilation. */ |
| |
| static int total_attempts, total_merges, total_extras, total_successes; |
| |
| |
| /* Vector mapping INSN_UIDs to cuids. |
| The cuids are like uids but increase monotonically always. |
| Combine always uses cuids so that it can compare them. |
| But actually renumbering the uids, which we used to do, |
| proves to be a bad idea because it makes it hard to compare |
| the dumps produced by earlier passes with those from later passes. */ |
| |
| static int *uid_cuid; |
| static int max_uid_cuid; |
| |
| /* Get the cuid of an insn. */ |
| |
| #define INSN_CUID(INSN) \ |
| (INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)]) |
| |
| /* In case BITS_PER_WORD == HOST_BITS_PER_WIDE_INT, shifting by |
| BITS_PER_WORD would invoke undefined behavior. Work around it. */ |
| |
| #define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \ |
| (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1) |
| |
| /* Maximum register number, which is the size of the tables below. */ |
| |
| static unsigned int combine_max_regno; |
| |
| struct reg_stat { |
| /* Record last point of death of (hard or pseudo) register n. */ |
| rtx last_death; |
| |
| /* Record last point of modification of (hard or pseudo) register n. */ |
| rtx last_set; |
| |
| /* The next group of fields allows the recording of the last value assigned |
| to (hard or pseudo) register n. We use this information to see if an |
| operation being processed is redundant given a prior operation performed |
| on the register. For example, an `and' with a constant is redundant if |
| all the zero bits are already known to be turned off. |
| |
| We use an approach similar to that used by cse, but change it in the |
| following ways: |
| |
| (1) We do not want to reinitialize at each label. |
| (2) It is useful, but not critical, to know the actual value assigned |
| to a register. Often just its form is helpful. |
| |
| Therefore, we maintain the following fields: |
| |
| last_set_value the last value assigned |
| last_set_label records the value of label_tick when the |
| register was assigned |
| last_set_table_tick records the value of label_tick when a |
| value using the register is assigned |
| last_set_invalid set to nonzero when it is not valid |
| to use the value of this register in some |
| register's value |
| |
| To understand the usage of these tables, it is important to understand |
| the distinction between the value in last_set_value being valid and |
| the register being validly contained in some other expression in the |
| table. |
| |
| (The next two parameters are out of date). |
| |
| reg_stat[i].last_set_value is valid if it is nonzero, and either |
| reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick. |
| |
| Register I may validly appear in any expression returned for the value |
| of another register if reg_n_sets[i] is 1. It may also appear in the |
| value for register J if reg_stat[j].last_set_invalid is zero, or |
| reg_stat[i].last_set_label < reg_stat[j].last_set_label. |
| |
| If an expression is found in the table containing a register which may |
| not validly appear in an expression, the register is replaced by |
| something that won't match, (clobber (const_int 0)). */ |
| |
| /* Record last value assigned to (hard or pseudo) register n. */ |
| |
| rtx last_set_value; |
| |
| /* Record the value of label_tick when an expression involving register n |
| is placed in last_set_value. */ |
| |
| int last_set_table_tick; |
| |
| /* Record the value of label_tick when the value for register n is placed in |
| last_set_value. */ |
| |
| int last_set_label; |
| |
| /* These fields are maintained in parallel with last_set_value and are |
| used to store the mode in which the register was last set, the bits |
| that were known to be zero when it was last set, and the number of |
| sign bits copies it was known to have when it was last set. */ |
| |
| unsigned HOST_WIDE_INT last_set_nonzero_bits; |
| char last_set_sign_bit_copies; |
| ENUM_BITFIELD(machine_mode) last_set_mode : 8; |
| |
| /* Set nonzero if references to register n in expressions should not be |
| used. last_set_invalid is set nonzero when this register is being |
| assigned to and last_set_table_tick == label_tick. */ |
| |
| char last_set_invalid; |
| |
| /* Some registers that are set more than once and used in more than one |
| basic block are nevertheless always set in similar ways. For example, |
| a QImode register may be loaded from memory in two places on a machine |
| where byte loads zero extend. |
| |
| We record in the following fields if a register has some leading bits |
| that are always equal to the sign bit, and what we know about the |
| nonzero bits of a register, specifically which bits are known to be |
| zero. |
| |
| If an entry is zero, it means that we don't know anything special. */ |
| |
| unsigned char sign_bit_copies; |
| |
| unsigned HOST_WIDE_INT nonzero_bits; |
| }; |
| |
| static struct reg_stat *reg_stat; |
| |
| /* Record the cuid of the last insn that invalidated memory |
| (anything that writes memory, and subroutine calls, but not pushes). */ |
| |
| static int mem_last_set; |
| |
| /* Record the cuid of the last CALL_INSN |
| so we can tell whether a potential combination crosses any calls. */ |
| |
| static int last_call_cuid; |
| |
| /* When `subst' is called, this is the insn that is being modified |
| (by combining in a previous insn). The PATTERN of this insn |
| is still the old pattern partially modified and it should not be |
| looked at, but this may be used to examine the successors of the insn |
| to judge whether a simplification is valid. */ |
| |
| static rtx subst_insn; |
| |
| /* This is the lowest CUID that `subst' is currently dealing with. |
| get_last_value will not return a value if the register was set at or |
| after this CUID. If not for this mechanism, we could get confused if |
| I2 or I1 in try_combine were an insn that used the old value of a register |
| to obtain a new value. In that case, we might erroneously get the |
| new value of the register when we wanted the old one. */ |
| |
| static int subst_low_cuid; |
| |
| /* This contains any hard registers that are used in newpat; reg_dead_at_p |
| must consider all these registers to be always live. */ |
| |
| static HARD_REG_SET newpat_used_regs; |
| |
| /* This is an insn to which a LOG_LINKS entry has been added. If this |
| insn is the earlier than I2 or I3, combine should rescan starting at |
| that location. */ |
| |
| static rtx added_links_insn; |
| |
| /* Basic block in which we are performing combines. */ |
| static basic_block this_basic_block; |
| |
| /* A bitmap indicating which blocks had registers go dead at entry. |
| After combine, we'll need to re-do global life analysis with |
| those blocks as starting points. */ |
| static sbitmap refresh_blocks; |
| |
| /* The following array records the insn_rtx_cost for every insn |
| in the instruction stream. */ |
| |
| static int *uid_insn_cost; |
| |
| /* Length of the currently allocated uid_insn_cost array. */ |
| |
| static int last_insn_cost; |
| |
| /* Incremented for each label. */ |
| |
| static int label_tick; |
| |
| /* Mode used to compute significance in reg_stat[].nonzero_bits. It is the |
| largest integer mode that can fit in HOST_BITS_PER_WIDE_INT. */ |
| |
| static enum machine_mode nonzero_bits_mode; |
| |
| /* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can |
| be safely used. It is zero while computing them and after combine has |
| completed. This former test prevents propagating values based on |
| previously set values, which can be incorrect if a variable is modified |
| in a loop. */ |
| |
| static int nonzero_sign_valid; |
| |
| |
| /* Record one modification to rtl structure |
| to be undone by storing old_contents into *where. |
| is_int is 1 if the contents are an int. */ |
| |
| struct undo |
| { |
| struct undo *next; |
| int is_int; |
| union {rtx r; int i;} old_contents; |
| union {rtx *r; int *i;} where; |
| }; |
| |
| /* Record a bunch of changes to be undone, up to MAX_UNDO of them. |
| num_undo says how many are currently recorded. |
| |
| other_insn is nonzero if we have modified some other insn in the process |
| of working on subst_insn. It must be verified too. */ |
| |
| struct undobuf |
| { |
| struct undo *undos; |
| struct undo *frees; |
| rtx other_insn; |
| }; |
| |
| static struct undobuf undobuf; |
| |
| /* Number of times the pseudo being substituted for |
| was found and replaced. */ |
| |
| static int n_occurrences; |
| |
| static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx, |
| enum machine_mode, |
| unsigned HOST_WIDE_INT, |
| unsigned HOST_WIDE_INT *); |
| static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx, |
| enum machine_mode, |
| unsigned int, unsigned int *); |
| static void do_SUBST (rtx *, rtx); |
| static void do_SUBST_INT (int *, int); |
| static void init_reg_last (void); |
| static void setup_incoming_promotions (void); |
| static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *); |
| static int cant_combine_insn_p (rtx); |
| static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *); |
| static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *); |
| static int contains_muldiv (rtx); |
| static rtx try_combine (rtx, rtx, rtx, int *); |
| static void undo_all (void); |
| static void undo_commit (void); |
| static rtx *find_split_point (rtx *, rtx); |
| static rtx subst (rtx, rtx, rtx, int, int); |
| static rtx combine_simplify_rtx (rtx, enum machine_mode, int); |
| static rtx simplify_if_then_else (rtx); |
| static rtx simplify_set (rtx); |
| static rtx simplify_logical (rtx); |
| static rtx expand_compound_operation (rtx); |
| static rtx expand_field_assignment (rtx); |
| static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT, |
| rtx, unsigned HOST_WIDE_INT, int, int, int); |
| static rtx extract_left_shift (rtx, int); |
| static rtx make_compound_operation (rtx, enum rtx_code); |
| static int get_pos_from_mask (unsigned HOST_WIDE_INT, |
| unsigned HOST_WIDE_INT *); |
| static rtx force_to_mode (rtx, enum machine_mode, |
| unsigned HOST_WIDE_INT, rtx, int); |
| static rtx if_then_else_cond (rtx, rtx *, rtx *); |
| static rtx known_cond (rtx, enum rtx_code, rtx, rtx); |
| static int rtx_equal_for_field_assignment_p (rtx, rtx); |
| static rtx make_field_assignment (rtx); |
| static rtx apply_distributive_law (rtx); |
| static rtx distribute_and_simplify_rtx (rtx, int); |
| static rtx simplify_and_const_int (rtx, enum machine_mode, rtx, |
| unsigned HOST_WIDE_INT); |
| static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code, |
| HOST_WIDE_INT, enum machine_mode, int *); |
| static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx, |
| int); |
| static int recog_for_combine (rtx *, rtx, rtx *); |
| static rtx gen_lowpart_for_combine (enum machine_mode, rtx); |
| static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *); |
| static void update_table_tick (rtx); |
| static void record_value_for_reg (rtx, rtx, rtx); |
| static void check_promoted_subreg (rtx, rtx); |
| static void record_dead_and_set_regs_1 (rtx, rtx, void *); |
| static void record_dead_and_set_regs (rtx); |
| static int get_last_value_validate (rtx *, rtx, int, int); |
| static rtx get_last_value (rtx); |
| static int use_crosses_set_p (rtx, int); |
| static void reg_dead_at_p_1 (rtx, rtx, void *); |
| static int reg_dead_at_p (rtx, rtx); |
| static void move_deaths (rtx, rtx, int, rtx, rtx *); |
| static int reg_bitfield_target_p (rtx, rtx); |
| static void distribute_notes (rtx, rtx, rtx, rtx); |
| static void distribute_links (rtx); |
| static void mark_used_regs_combine (rtx); |
| static int insn_cuid (rtx); |
| static void record_promoted_value (rtx, rtx); |
| static rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx); |
| static enum rtx_code combine_reversed_comparison_code (rtx); |
| static int unmentioned_reg_p_1 (rtx *, void *); |
| static bool unmentioned_reg_p (rtx, rtx); |
| |
| |
| /* It is not safe to use ordinary gen_lowpart in combine. |
| See comments in gen_lowpart_for_combine. */ |
| #undef RTL_HOOKS_GEN_LOWPART |
| #define RTL_HOOKS_GEN_LOWPART gen_lowpart_for_combine |
| |
| #undef RTL_HOOKS_REG_NONZERO_REG_BITS |
| #define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_for_combine |
| |
| #undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES |
| #define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_for_combine |
| |
| static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER; |
| |
| |
| /* Substitute NEWVAL, an rtx expression, into INTO, a place in some |
| insn. The substitution can be undone by undo_all. If INTO is already |
| set to NEWVAL, do not record this change. Because computing NEWVAL might |
| also call SUBST, we have to compute it before we put anything into |
| the undo table. */ |
| |
| static void |
| do_SUBST (rtx *into, rtx newval) |
| { |
| struct undo *buf; |
| rtx oldval = *into; |
| |
| if (oldval == newval) |
| return; |
| |
| /* We'd like to catch as many invalid transformations here as |
| possible. Unfortunately, there are way too many mode changes |
| that are perfectly valid, so we'd waste too much effort for |
| little gain doing the checks here. Focus on catching invalid |
| transformations involving integer constants. */ |
| if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT |
| && GET_CODE (newval) == CONST_INT) |
| { |
| /* Sanity check that we're replacing oldval with a CONST_INT |
| that is a valid sign-extension for the original mode. */ |
| gcc_assert (INTVAL (newval) |
| == trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval))); |
| |
| /* Replacing the operand of a SUBREG or a ZERO_EXTEND with a |
| CONST_INT is not valid, because after the replacement, the |
| original mode would be gone. Unfortunately, we can't tell |
| when do_SUBST is called to replace the operand thereof, so we |
| perform this test on oldval instead, checking whether an |
| invalid replacement took place before we got here. */ |
| gcc_assert (!(GET_CODE (oldval) == SUBREG |
| && GET_CODE (SUBREG_REG (oldval)) == CONST_INT)); |
| gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND |
| && GET_CODE (XEXP (oldval, 0)) == CONST_INT)); |
| } |
| |
| if (undobuf.frees) |
| buf = undobuf.frees, undobuf.frees = buf->next; |
| else |
| buf = xmalloc (sizeof (struct undo)); |
| |
| buf->is_int = 0; |
| buf->where.r = into; |
| buf->old_contents.r = oldval; |
| *into = newval; |
| |
| buf->next = undobuf.undos, undobuf.undos = buf; |
| } |
| |
| #define SUBST(INTO, NEWVAL) do_SUBST(&(INTO), (NEWVAL)) |
| |
| /* Similar to SUBST, but NEWVAL is an int expression. Note that substitution |
| for the value of a HOST_WIDE_INT value (including CONST_INT) is |
| not safe. */ |
| |
| static void |
| do_SUBST_INT (int *into, int newval) |
| { |
| struct undo *buf; |
| int oldval = *into; |
| |
| if (oldval == newval) |
| return; |
| |
| if (undobuf.frees) |
| buf = undobuf.frees, undobuf.frees = buf->next; |
| else |
| buf = xmalloc (sizeof (struct undo)); |
| |
| buf->is_int = 1; |
| buf->where.i = into; |
| buf->old_contents.i = oldval; |
| *into = newval; |
| |
| buf->next = undobuf.undos, undobuf.undos = buf; |
| } |
| |
| #define SUBST_INT(INTO, NEWVAL) do_SUBST_INT(&(INTO), (NEWVAL)) |
| |
| /* Subroutine of try_combine. Determine whether the combine replacement |
| patterns NEWPAT and NEWI2PAT are cheaper according to insn_rtx_cost |
| that the original instruction sequence I1, I2 and I3. Note that I1 |
| and/or NEWI2PAT may be NULL_RTX. This function returns false, if the |
| costs of all instructions can be estimated, and the replacements are |
| more expensive than the original sequence. */ |
| |
| static bool |
| combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat) |
| { |
| int i1_cost, i2_cost, i3_cost; |
| int new_i2_cost, new_i3_cost; |
| int old_cost, new_cost; |
| |
| /* Lookup the original insn_rtx_costs. */ |
| i2_cost = INSN_UID (i2) <= last_insn_cost |
| ? uid_insn_cost[INSN_UID (i2)] : 0; |
| i3_cost = INSN_UID (i3) <= last_insn_cost |
| ? uid_insn_cost[INSN_UID (i3)] : 0; |
| |
| if (i1) |
| { |
| i1_cost = INSN_UID (i1) <= last_insn_cost |
| ? uid_insn_cost[INSN_UID (i1)] : 0; |
| old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0) |
| ? i1_cost + i2_cost + i3_cost : 0; |
| } |
| else |
| { |
| old_cost = (i2_cost > 0 && i3_cost > 0) ? i2_cost + i3_cost : 0; |
| i1_cost = 0; |
| } |
| |
| /* Calculate the replacement insn_rtx_costs. */ |
| new_i3_cost = insn_rtx_cost (newpat); |
| if (newi2pat) |
| { |
| new_i2_cost = insn_rtx_cost (newi2pat); |
| new_cost = (new_i2_cost > 0 && new_i3_cost > 0) |
| ? new_i2_cost + new_i3_cost : 0; |
| } |
| else |
| { |
| new_cost = new_i3_cost; |
| new_i2_cost = 0; |
| } |
| |
| if (undobuf.other_insn) |
| { |
| int old_other_cost, new_other_cost; |
| |
| old_other_cost = (INSN_UID (undobuf.other_insn) <= last_insn_cost |
| ? uid_insn_cost[INSN_UID (undobuf.other_insn)] : 0); |
| new_other_cost = insn_rtx_cost (PATTERN (undobuf.other_insn)); |
| if (old_other_cost > 0 && new_other_cost > 0) |
| { |
| old_cost += old_other_cost; |
| new_cost += new_other_cost; |
| } |
| else |
| old_cost = 0; |
| } |
| |
| /* Disallow this recombination if both new_cost and old_cost are |
| greater than zero, and new_cost is greater than old cost. */ |
| if (old_cost > 0 |
| && new_cost > old_cost) |
| { |
| if (dump_file) |
| { |
| if (i1) |
| { |
| fprintf (dump_file, |
| "rejecting combination of insns %d, %d and %d\n", |
| INSN_UID (i1), INSN_UID (i2), INSN_UID (i3)); |
| fprintf (dump_file, "original costs %d + %d + %d = %d\n", |
| i1_cost, i2_cost, i3_cost, old_cost); |
| } |
| else |
| { |
| fprintf (dump_file, |
| "rejecting combination of insns %d and %d\n", |
| INSN_UID (i2), INSN_UID (i3)); |
| fprintf (dump_file, "original costs %d + %d = %d\n", |
| i2_cost, i3_cost, old_cost); |
| } |
| |
| if (newi2pat) |
| { |
| fprintf (dump_file, "replacement costs %d + %d = %d\n", |
| new_i2_cost, new_i3_cost, new_cost); |
| } |
| else |
| fprintf (dump_file, "replacement cost %d\n", new_cost); |
| } |
| |
| return false; |
| } |
| |
| /* Update the uid_insn_cost array with the replacement costs. */ |
| uid_insn_cost[INSN_UID (i2)] = new_i2_cost; |
| uid_insn_cost[INSN_UID (i3)] = new_i3_cost; |
| if (i1) |
| uid_insn_cost[INSN_UID (i1)] = 0; |
| |
| return true; |
| } |
| |
| /* Main entry point for combiner. F is the first insn of the function. |
| NREGS is the first unused pseudo-reg number. |
| |
| Return nonzero if the combiner has turned an indirect jump |
| instruction into a direct jump. */ |
| int |
| combine_instructions (rtx f, unsigned int nregs) |
| { |
| rtx insn, next; |
| #ifdef HAVE_cc0 |
| rtx prev; |
| #endif |
| int i; |
| rtx links, nextlinks; |
| |
| int new_direct_jump_p = 0; |
| |
| combine_attempts = 0; |
| combine_merges = 0; |
| combine_extras = 0; |
| combine_successes = 0; |
| |
| combine_max_regno = nregs; |
| |
| rtl_hooks = combine_rtl_hooks; |
| |
| reg_stat = xcalloc (nregs, sizeof (struct reg_stat)); |
| |
| init_recog_no_volatile (); |
| |
| /* Compute maximum uid value so uid_cuid can be allocated. */ |
| |
| for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) |
| if (INSN_UID (insn) > i) |
| i = INSN_UID (insn); |
| |
| uid_cuid = xmalloc ((i + 1) * sizeof (int)); |
| max_uid_cuid = i; |
| |
| nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); |
| |
| /* Don't use reg_stat[].nonzero_bits when computing it. This can cause |
| problems when, for example, we have j <<= 1 in a loop. */ |
| |
| nonzero_sign_valid = 0; |
| |
| /* Compute the mapping from uids to cuids. |
| Cuids are numbers assigned to insns, like uids, |
| except that cuids increase monotonically through the code. |
| |
| Scan all SETs and see if we can deduce anything about what |
| bits are known to be zero for some registers and how many copies |
| of the sign bit are known to exist for those registers. |
| |
| Also set any known values so that we can use it while searching |
| for what bits are known to be set. */ |
| |
| label_tick = 1; |
| |
| setup_incoming_promotions (); |
| |
| refresh_blocks = sbitmap_alloc (last_basic_block); |
| sbitmap_zero (refresh_blocks); |
| |
| /* Allocate array of current insn_rtx_costs. */ |
| uid_insn_cost = xcalloc (max_uid_cuid + 1, sizeof (int)); |
| last_insn_cost = max_uid_cuid; |
| |
| for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) |
| { |
| uid_cuid[INSN_UID (insn)] = ++i; |
| subst_low_cuid = i; |
| subst_insn = insn; |
| |
| if (INSN_P (insn)) |
| { |
| note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies, |
| NULL); |
| record_dead_and_set_regs (insn); |
| |
| #ifdef AUTO_INC_DEC |
| for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) |
| if (REG_NOTE_KIND (links) == REG_INC) |
| set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX, |
| NULL); |
| #endif |
| |
| /* Record the current insn_rtx_cost of this instruction. */ |
| if (NONJUMP_INSN_P (insn)) |
| uid_insn_cost[INSN_UID (insn)] = insn_rtx_cost (PATTERN (insn)); |
| if (dump_file) |
| fprintf(dump_file, "insn_cost %d: %d\n", |
| INSN_UID (insn), uid_insn_cost[INSN_UID (insn)]); |
| } |
| |
| if (LABEL_P (insn)) |
| label_tick++; |
| } |
| |
| nonzero_sign_valid = 1; |
| |
| /* Now scan all the insns in forward order. */ |
| |
| label_tick = 1; |
| last_call_cuid = 0; |
| mem_last_set = 0; |
| init_reg_last (); |
| setup_incoming_promotions (); |
| |
| FOR_EACH_BB (this_basic_block) |
| { |
| for (insn = BB_HEAD (this_basic_block); |
| insn != NEXT_INSN (BB_END (this_basic_block)); |
| insn = next ? next : NEXT_INSN (insn)) |
| { |
| next = 0; |
| |
| if (LABEL_P (insn)) |
| label_tick++; |
| |
| else if (INSN_P (insn)) |
| { |
| /* See if we know about function return values before this |
| insn based upon SUBREG flags. */ |
| check_promoted_subreg (insn, PATTERN (insn)); |
| |
| /* Try this insn with each insn it links back to. */ |
| |
| for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) |
| if ((next = try_combine (insn, XEXP (links, 0), |
| NULL_RTX, &new_direct_jump_p)) != 0) |
| goto retry; |
| |
| /* Try each sequence of three linked insns ending with this one. */ |
| |
| for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) |
| { |
| rtx link = XEXP (links, 0); |
| |
| /* If the linked insn has been replaced by a note, then there |
| is no point in pursuing this chain any further. */ |
| if (NOTE_P (link)) |
| continue; |
| |
| for (nextlinks = LOG_LINKS (link); |
| nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, link, |
| XEXP (nextlinks, 0), |
| &new_direct_jump_p)) != 0) |
| goto retry; |
| } |
| |
| #ifdef HAVE_cc0 |
| /* Try to combine a jump insn that uses CC0 |
| with a preceding insn that sets CC0, and maybe with its |
| logical predecessor as well. |
| This is how we make decrement-and-branch insns. |
| We need this special code because data flow connections |
| via CC0 do not get entered in LOG_LINKS. */ |
| |
| if (JUMP_P (insn) |
| && (prev = prev_nonnote_insn (insn)) != 0 |
| && NONJUMP_INSN_P (prev) |
| && sets_cc0_p (PATTERN (prev))) |
| { |
| if ((next = try_combine (insn, prev, |
| NULL_RTX, &new_direct_jump_p)) != 0) |
| goto retry; |
| |
| for (nextlinks = LOG_LINKS (prev); nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, prev, |
| XEXP (nextlinks, 0), |
| &new_direct_jump_p)) != 0) |
| goto retry; |
| } |
| |
| /* Do the same for an insn that explicitly references CC0. */ |
| if (NONJUMP_INSN_P (insn) |
| && (prev = prev_nonnote_insn (insn)) != 0 |
| && NONJUMP_INSN_P (prev) |
| && sets_cc0_p (PATTERN (prev)) |
| && GET_CODE (PATTERN (insn)) == SET |
| && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn)))) |
| { |
| if ((next = try_combine (insn, prev, |
| NULL_RTX, &new_direct_jump_p)) != 0) |
| goto retry; |
| |
| for (nextlinks = LOG_LINKS (prev); nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, prev, |
| XEXP (nextlinks, 0), |
| &new_direct_jump_p)) != 0) |
| goto retry; |
| } |
| |
| /* Finally, see if any of the insns that this insn links to |
| explicitly references CC0. If so, try this insn, that insn, |
| and its predecessor if it sets CC0. */ |
| for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) |
| if (NONJUMP_INSN_P (XEXP (links, 0)) |
| && GET_CODE (PATTERN (XEXP (links, 0))) == SET |
| && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0)))) |
| && (prev = prev_nonnote_insn (XEXP (links, 0))) != 0 |
| && NONJUMP_INSN_P (prev) |
| && sets_cc0_p (PATTERN (prev)) |
| && (next = try_combine (insn, XEXP (links, 0), |
| prev, &new_direct_jump_p)) != 0) |
| goto retry; |
| #endif |
| |
| /* Try combining an insn with two different insns whose results it |
| uses. */ |
| for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) |
| for (nextlinks = XEXP (links, 1); nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, XEXP (links, 0), |
| XEXP (nextlinks, 0), |
| &new_direct_jump_p)) != 0) |
| goto retry; |
| |
| /* Try this insn with each REG_EQUAL note it links back to. */ |
| for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) |
| { |
| rtx set, note; |
| rtx temp = XEXP (links, 0); |
| if ((set = single_set (temp)) != 0 |
| && (note = find_reg_equal_equiv_note (temp)) != 0 |
| && GET_CODE (XEXP (note, 0)) != EXPR_LIST |
| /* Avoid using a register that may already been marked |
| dead by an earlier instruction. */ |
| && ! unmentioned_reg_p (XEXP (note, 0), SET_SRC (set))) |
| { |
| /* Temporarily replace the set's source with the |
| contents of the REG_EQUAL note. The insn will |
| be deleted or recognized by try_combine. */ |
| rtx orig = SET_SRC (set); |
| SET_SRC (set) = XEXP (note, 0); |
| next = try_combine (insn, temp, NULL_RTX, |
| &new_direct_jump_p); |
| if (next) |
| goto retry; |
| SET_SRC (set) = orig; |
| } |
| } |
| |
| if (!NOTE_P (insn)) |
| record_dead_and_set_regs (insn); |
| |
| retry: |
| ; |
| } |
| } |
| } |
| clear_bb_flags (); |
| |
| EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, i, |
| BASIC_BLOCK (i)->flags |= BB_DIRTY); |
| new_direct_jump_p |= purge_all_dead_edges (0); |
| delete_noop_moves (); |
| |
| update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES, |
| PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE |
| | PROP_KILL_DEAD_CODE); |
| |
| /* Clean up. */ |
| sbitmap_free (refresh_blocks); |
| free (uid_insn_cost); |
| free (reg_stat); |
| free (uid_cuid); |
| |
| { |
| struct undo *undo, *next; |
| for (undo = undobuf.frees; undo; undo = next) |
| { |
| next = undo->next; |
| free (undo); |
| } |
| undobuf.frees = 0; |
| } |
| |
| total_attempts += combine_attempts; |
| total_merges += combine_merges; |
| total_extras += combine_extras; |
| total_successes += combine_successes; |
| |
| nonzero_sign_valid = 0; |
| rtl_hooks = general_rtl_hooks; |
| |
| /* Make recognizer allow volatile MEMs again. */ |
| init_recog (); |
| |
| return new_direct_jump_p; |
| } |
| |
| /* Wipe the last_xxx fields of reg_stat in preparation for another pass. */ |
| |
| static void |
| init_reg_last (void) |
| { |
| unsigned int i; |
| for (i = 0; i < combine_max_regno; i++) |
| memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies)); |
| } |
| |
| /* Set up any promoted values for incoming argument registers. */ |
| |
| static void |
| setup_incoming_promotions (void) |
| { |
| unsigned int regno; |
| rtx reg; |
| enum machine_mode mode; |
| int unsignedp; |
| rtx first = get_insns (); |
| |
| if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl))) |
| { |
| for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) |
| /* Check whether this register can hold an incoming pointer |
| argument. FUNCTION_ARG_REGNO_P tests outgoing register |
| numbers, so translate if necessary due to register windows. */ |
| if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno)) |
| && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0) |
| { |
| record_value_for_reg |
| (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND |
| : SIGN_EXTEND), |
| GET_MODE (reg), |
| gen_rtx_CLOBBER (mode, const0_rtx))); |
| } |
| } |
| } |
| |
| /* Called via note_stores. If X is a pseudo that is narrower than |
| HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero. |
| |
| If we are setting only a portion of X and we can't figure out what |
| portion, assume all bits will be used since we don't know what will |
| be happening. |
| |
| Similarly, set how many bits of X are known to be copies of the sign bit |
| at all locations in the function. This is the smallest number implied |
| by any set of X. */ |
| |
| static void |
| set_nonzero_bits_and_sign_copies (rtx x, rtx set, |
| void *data ATTRIBUTE_UNUSED) |
| { |
| unsigned int num; |
| |
| if (REG_P (x) |
| && REGNO (x) >= FIRST_PSEUDO_REGISTER |
| /* If this register is undefined at the start of the file, we can't |
| say what its contents were. */ |
| && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, REGNO (x)) |
| && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT) |
| { |
| if (set == 0 || GET_CODE (set) == CLOBBER) |
| { |
| reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x)); |
| reg_stat[REGNO (x)].sign_bit_copies = 1; |
| return; |
| } |
| |
| /* If this is a complex assignment, see if we can convert it into a |
| simple assignment. */ |
| set = expand_field_assignment (set); |
| |
| /* If this is a simple assignment, or we have a paradoxical SUBREG, |
| set what we know about X. */ |
| |
| if (SET_DEST (set) == x |
| || (GET_CODE (SET_DEST (set)) == SUBREG |
| && (GET_MODE_SIZE (GET_MODE (SET_DEST (set))) |
| > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set))))) |
| && SUBREG_REG (SET_DEST (set)) == x)) |
| { |
| rtx src = SET_SRC (set); |
| |
| #ifdef SHORT_IMMEDIATES_SIGN_EXTEND |
| /* If X is narrower than a word and SRC is a non-negative |
| constant that would appear negative in the mode of X, |
| sign-extend it for use in reg_stat[].nonzero_bits because some |
| machines (maybe most) will actually do the sign-extension |
| and this is the conservative approach. |
| |
| ??? For 2.5, try to tighten up the MD files in this regard |
| instead of this kludge. */ |
| |
| if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD |
| && GET_CODE (src) == CONST_INT |
| && INTVAL (src) > 0 |
| && 0 != (INTVAL (src) |
| & ((HOST_WIDE_INT) 1 |
| << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))) |
| src = GEN_INT (INTVAL (src) |
| | ((HOST_WIDE_INT) (-1) |
| << GET_MODE_BITSIZE (GET_MODE (x)))); |
| #endif |
| |
| /* Don't call nonzero_bits if it cannot change anything. */ |
| if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0) |
| reg_stat[REGNO (x)].nonzero_bits |
| |= nonzero_bits (src, nonzero_bits_mode); |
| num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); |
| if (reg_stat[REGNO (x)].sign_bit_copies == 0 |
| || reg_stat[REGNO (x)].sign_bit_copies > num) |
| reg_stat[REGNO (x)].sign_bit_copies = num; |
| } |
| else |
| { |
| reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x)); |
| reg_stat[REGNO (x)].sign_bit_copies = 1; |
| } |
| } |
| } |
| |
| /* See if INSN can be combined into I3. PRED and SUCC are optionally |
| insns that were previously combined into I3 or that will be combined |
| into the merger of INSN and I3. |
| |
| Return 0 if the combination is not allowed for any reason. |
| |
| If the combination is allowed, *PDEST will be set to the single |
| destination of INSN and *PSRC to the single source, and this function |
| will return 1. */ |
| |
| static int |
| can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ, |
| rtx *pdest, rtx *psrc) |
| { |
| int i; |
| rtx set = 0, src, dest; |
| rtx p; |
| #ifdef AUTO_INC_DEC |
| rtx link; |
| #endif |
| int all_adjacent = (succ ? (next_active_insn (insn) == succ |
| && next_active_insn (succ) == i3) |
| : next_active_insn (insn) == i3); |
| |
| /* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0. |
| or a PARALLEL consisting of such a SET and CLOBBERs. |
| |
| If INSN has CLOBBER parallel parts, ignore them for our processing. |
| By definition, these happen during the execution of the insn. When it |
| is merged with another insn, all bets are off. If they are, in fact, |
| needed and aren't also supplied in I3, they may be added by |
| recog_for_combine. Otherwise, it won't match. |
| |
| We can also ignore a SET whose SET_DEST is mentioned in a REG_UNUSED |
| note. |
| |
| Get the source and destination of INSN. If more than one, can't |
| combine. */ |
| |
| if (GET_CODE (PATTERN (insn)) == SET) |
| set = PATTERN (insn); |
| else if (GET_CODE (PATTERN (insn)) == PARALLEL |
| && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) |
| { |
| for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) |
| { |
| rtx elt = XVECEXP (PATTERN (insn), 0, i); |
| rtx note; |
| |
| switch (GET_CODE (elt)) |
| { |
| /* This is important to combine floating point insns |
| for the SH4 port. */ |
| case USE: |
| /* Combining an isolated USE doesn't make sense. |
| We depend here on combinable_i3pat to reject them. */ |
| /* The code below this loop only verifies that the inputs of |
| the SET in INSN do not change. We call reg_set_between_p |
| to verify that the REG in the USE does not change between |
| I3 and INSN. |
| If the USE in INSN was for a pseudo register, the matching |
| insn pattern will likely match any register; combining this |
| with any other USE would only be safe if we knew that the |
| used registers have identical values, or if there was |
| something to tell them apart, e.g. different modes. For |
| now, we forgo such complicated tests and simply disallow |
| combining of USES of pseudo registers with any other USE. */ |
| if (REG_P (XEXP (elt, 0)) |
| && GET_CODE (PATTERN (i3)) == PARALLEL) |
| { |
| rtx i3pat = PATTERN (i3); |
| int i = XVECLEN (i3pat, 0) - 1; |
| unsigned int regno = REGNO (XEXP (elt, 0)); |
| |
| do |
| { |
| rtx i3elt = XVECEXP (i3pat, 0, i); |
| |
| if (GET_CODE (i3elt) == USE |
| && REG_P (XEXP (i3elt, 0)) |
| && (REGNO (XEXP (i3elt, 0)) == regno |
| ? reg_set_between_p (XEXP (elt, 0), |
| PREV_INSN (insn), i3) |
| : regno >= FIRST_PSEUDO_REGISTER)) |
| return 0; |
| } |
| while (--i >= 0); |
| } |
| break; |
| |
| /* We can ignore CLOBBERs. */ |
| case CLOBBER: |
| break; |
| |
| case SET: |
| /* Ignore SETs whose result isn't used but not those that |
| have side-effects. */ |
| if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt)) |
| && (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX)) |
| || INTVAL (XEXP (note, 0)) <= 0) |
| && ! side_effects_p (elt)) |
| break; |
| |
| /* If we have already found a SET, this is a second one and |
| so we cannot combine with this insn. */ |
| if (set) |
| return 0; |
| |
| set = elt; |
| break; |
| |
| default: |
| /* Anything else means we can't combine. */ |
| return 0; |
| } |
| } |
| |
| if (set == 0 |
| /* If SET_SRC is an ASM_OPERANDS we can't throw away these CLOBBERs, |
| so don't do anything with it. */ |
| || GET_CODE (SET_SRC (set)) == ASM_OPERANDS) |
| return 0; |
| } |
| else |
| return 0; |
| |
| if (set == 0) |
| return 0; |
| |
| set = expand_field_assignment (set); |
| src = SET_SRC (set), dest = SET_DEST (set); |
| |
| /* Don't eliminate a store in the stack pointer. */ |
| if (dest == stack_pointer_rtx |
| /* Don't combine with an insn that sets a register to itself if it has |
| a REG_EQUAL note. This may be part of a REG_NO_CONFLICT sequence. */ |
| || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX)) |
| /* Can't merge an ASM_OPERANDS. */ |
| || GET_CODE (src) == ASM_OPERANDS |
| /* Can't merge a function call. */ |
| || GET_CODE (src) == CALL |
| /* Don't eliminate a function call argument. */ |
| || (CALL_P (i3) |
| && (find_reg_fusage (i3, USE, dest) |
| || (REG_P (dest) |
| && REGNO (dest) < FIRST_PSEUDO_REGISTER |
| && global_regs[REGNO (dest)]))) |
| /* Don't substitute into an incremented register. */ |
| || FIND_REG_INC_NOTE (i3, dest) |
| || (succ && FIND_REG_INC_NOTE (succ, dest)) |
| /* Don't substitute into a non-local goto, this confuses CFG. */ |
| || (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX)) |
| #if 0 |
| /* Don't combine the end of a libcall into anything. */ |
| /* ??? This gives worse code, and appears to be unnecessary, since no |
| pass after flow uses REG_LIBCALL/REG_RETVAL notes. Local-alloc does |
| use REG_RETVAL notes for noconflict blocks, but other code here |
| makes sure that those insns don't disappear. */ |
| || find_reg_note (insn, REG_RETVAL, NULL_RTX) |
| #endif |
| /* Make sure that DEST is not used after SUCC but before I3. */ |
| || (succ && ! all_adjacent |
| && reg_used_between_p (dest, succ, i3)) |
| /* Make sure that the value that is to be substituted for the register |
| does not use any registers whose values alter in between. However, |
| If the insns are adjacent, a use can't cross a set even though we |
| think it might (this can happen for a sequence of insns each setting |
| the same destination; last_set of that register might point to |
| a NOTE). If INSN has a REG_EQUIV note, the register is always |
| equivalent to the memory so the substitution is valid even if there |
| are intervening stores. Also, don't move a volatile asm or |
| UNSPEC_VOLATILE across any other insns. */ |
| || (! all_adjacent |
| && (((!MEM_P (src) |
| || ! find_reg_note (insn, REG_EQUIV, src)) |
| && use_crosses_set_p (src, INSN_CUID (insn))) |
| || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src)) |
| || GET_CODE (src) == UNSPEC_VOLATILE)) |
| /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get |
| better register allocation by not doing the combine. */ |
| || find_reg_note (i3, REG_NO_CONFLICT, dest) |
| || (succ && find_reg_note (succ, REG_NO_CONFLICT, dest)) |
| /* Don't combine across a CALL_INSN, because that would possibly |
| change whether the life span of some REGs crosses calls or not, |
| and it is a pain to update that information. |
| Exception: if source is a constant, moving it later can't hurt. |
| Accept that special case, because it helps -fforce-addr a lot. */ |
| || (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src))) |
| return 0; |
| |
| /* DEST must either be a REG or CC0. */ |
| if (REG_P (dest)) |
| { |
| /* If register alignment is being enforced for multi-word items in all |
| cases except for parameters, it is possible to have a register copy |
| insn referencing a hard register that is not allowed to contain the |
| mode being copied and which would not be valid as an operand of most |
| insns. Eliminate this problem by not combining with such an insn. |
| |
| Also, on some machines we don't want to extend the life of a hard |
| register. */ |
| |
| if (REG_P (src) |
| && ((REGNO (dest) < FIRST_PSEUDO_REGISTER |
| && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest))) |
| /* Don't extend the life of a hard register unless it is |
| user variable (if we have few registers) or it can't |
| fit into the desired register (meaning something special |
| is going on). |
| Also avoid substituting a return register into I3, because |
| reload can't handle a conflict with constraints of other |
| inputs. */ |
| || (REGNO (src) < FIRST_PSEUDO_REGISTER |
| && ! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))))) |
| return 0; |
| } |
| else if (GET_CODE (dest) != CC0) |
| return 0; |
| |
| |
| if (GET_CODE (PATTERN (i3)) == PARALLEL) |
| for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--) |
| if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER) |
| { |
| /* Don't substitute for a register intended as a clobberable |
| operand. */ |
| rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0); |
| if (rtx_equal_p (reg, dest)) |
| return 0; |
| |
| /* If the clobber represents an earlyclobber operand, we must not |
| substitute an expression containing the clobbered register. |
| As we do not analyze the constraint strings here, we have to |
| make the conservative assumption. However, if the register is |
| a fixed hard reg, the clobber cannot represent any operand; |
| we leave it up to the machine description to either accept or |
| reject use-and-clobber patterns. */ |
| if (!REG_P (reg) |
| || REGNO (reg) >= FIRST_PSEUDO_REGISTER |
| || !fixed_regs[REGNO (reg)]) |
| if (reg_overlap_mentioned_p (reg, src)) |
| return 0; |
| } |
| |
| /* If INSN contains anything volatile, or is an `asm' (whether volatile |
| or not), reject, unless nothing volatile comes between it and I3 */ |
| |
| if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src)) |
| { |
| /* Make sure succ doesn't contain a volatile reference. */ |
| if (succ != 0 && volatile_refs_p (PATTERN (succ))) |
| return 0; |
| |
| for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p)) |
| if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p))) |
| return 0; |
| } |
| |
| /* If INSN is an asm, and DEST is a hard register, reject, since it has |
| to be an explicit register variable, and was chosen for a reason. */ |
| |
| if (GET_CODE (src) == ASM_OPERANDS |
| && REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER) |
| return 0; |
| |
| /* If there are any volatile insns between INSN and I3, reject, because |
| they might affect machine state. */ |
| |
| for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p)) |
| if (INSN_P (p) && p != succ && volatile_insn_p (PATTERN (p))) |
| return 0; |
| |
| /* If INSN contains an autoincrement or autodecrement, make sure that |
| register is not used between there and I3, and not already used in |
| I3 either. Neither must it be used in PRED or SUCC, if they exist. |
| Also insist that I3 not be a jump; if it were one |
| and the incremented register were spilled, we would lose. */ |
| |
| #ifdef AUTO_INC_DEC |
| for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) |
| if (REG_NOTE_KIND (link) == REG_INC |
| && (JUMP_P (i3) |
| || reg_used_between_p (XEXP (link, 0), insn, i3) |
| || (pred != NULL_RTX |
| && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred))) |
| || (succ != NULL_RTX |
| && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ))) |
| || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3)))) |
| return 0; |
| #endif |
| |
| #ifdef HAVE_cc0 |
| /* Don't combine an insn that follows a CC0-setting insn. |
| An insn that uses CC0 must not be separated from the one that sets it. |
| We do, however, allow I2 to follow a CC0-setting insn if that insn |
| is passed as I1; in that case it will be deleted also. |
| We also allow combining in this case if all the insns are adjacent |
| because that would leave the two CC0 insns adjacent as well. |
| It would be more logical to test whether CC0 occurs inside I1 or I2, |
| but that would be much slower, and this ought to be equivalent. */ |
| |
| p = prev_nonnote_insn (insn); |
| if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p)) |
| && ! all_adjacent) |
| return 0; |
| #endif |
| |
| /* If we get here, we have passed all the tests and the combination is |
| to be allowed. */ |
| |
| *pdest = dest; |
| *psrc = src; |
| |
| return 1; |
| } |
| |
| /* LOC is the location within I3 that contains its pattern or the component |
| of a PARALLEL of the pattern. We validate that it is valid for combining. |
| |
| One problem is if I3 modifies its output, as opposed to replacing it |
| entirely, we can't allow the output to contain I2DEST or I1DEST as doing |
| so would produce an insn that is not equivalent to the original insns. |
| |
| Consider: |
| |
| (set (reg:DI 101) (reg:DI 100)) |
| (set (subreg:SI (reg:DI 101) 0) <foo>) |
| |
| This is NOT equivalent to: |
| |
| (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>) |
| (set (reg:DI 101) (reg:DI 100))]) |
| |
| Not only does this modify 100 (in which case it might still be valid |
| if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100. |
| |
| We can also run into a problem if I2 sets a register that I1 |
| uses and I1 gets directly substituted into I3 (not via I2). In that |
| case, we would be getting the wrong value of I2DEST into I3, so we |
| must reject the combination. This case occurs when I2 and I1 both |
| feed into I3, rather than when I1 feeds into I2, which feeds into I3. |
| If I1_NOT_IN_SRC is nonzero, it means that finding I1 in the source |
| of a SET must prevent combination from occurring. |
| |
| Before doing the above check, we first try to expand a field assignment |
| into a set of logical operations. |
| |
| If PI3_DEST_KILLED is nonzero, it is a pointer to a location in which |
| we place a register that is both set and used within I3. If more than one |
| such register is detected, we fail. |
| |
| Return 1 if the combination is valid, zero otherwise. */ |
| |
| static int |
| combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest, |
| int i1_not_in_src, rtx *pi3dest_killed) |
| { |
| rtx x = *loc; |
| |
| if (GET_CODE (x) == SET) |
| { |
| rtx set = x ; |
| rtx dest = SET_DEST (set); |
| rtx src = SET_SRC (set); |
| rtx inner_dest = dest; |
| |
| while (GET_CODE (inner_dest) == STRICT_LOW_PART |
| || GET_CODE (inner_dest) == SUBREG |
| || GET_CODE (inner_dest) == ZERO_EXTRACT) |
| inner_dest = XEXP (inner_dest, 0); |
| |
| /* Check for the case where I3 modifies its output, as discussed |
| above. We don't want to prevent pseudos from being combined |
| into the address of a MEM, so only prevent the combination if |
| i1 or i2 set the same MEM. */ |
| if ((inner_dest != dest && |
| (!MEM_P (inner_dest) |
| || rtx_equal_p (i2dest, inner_dest) |
| || (i1dest && rtx_equal_p (i1dest, inner_dest))) |
| && (reg_overlap_mentioned_p (i2dest, inner_dest) |
| || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest)))) |
| |
| /* This is the same test done in can_combine_p except we can't test |
| all_adjacent; we don't have to, since this instruction will stay |
| in place, thus we are not considering increasing the lifetime of |
| INNER_DEST. |
| |
| Also, if this insn sets a function argument, combining it with |
| something that might need a spill could clobber a previous |
| function argument; the all_adjacent test in can_combine_p also |
| checks this; here, we do a more specific test for this case. */ |
| |
| || (REG_P (inner_dest) |
| && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER |
| && (! HARD_REGNO_MODE_OK (REGNO (inner_dest), |
| GET_MODE (inner_dest)))) |
| || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src))) |
| return 0; |
| |
| /* If DEST is used in I3, it is being killed in this insn, |
| so record that for later. |
| Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the |
| STACK_POINTER_REGNUM, since these are always considered to be |
| live. Similarly for ARG_POINTER_REGNUM if it is fixed. */ |
| if (pi3dest_killed && REG_P (dest) |
| && reg_referenced_p (dest, PATTERN (i3)) |
| && REGNO (dest) != FRAME_POINTER_REGNUM |
| #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM |
| && REGNO (dest) != HARD_FRAME_POINTER_REGNUM |
| #endif |
| #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM |
| && (REGNO (dest) != ARG_POINTER_REGNUM |
| || ! fixed_regs [REGNO (dest)]) |
| #endif |
| && REGNO (dest) != STACK_POINTER_REGNUM) |
| { |
| if (*pi3dest_killed) |
| return 0; |
| |
| *pi3dest_killed = dest; |
| } |
| } |
| |
| else if (GET_CODE (x) == PARALLEL) |
| { |
| int i; |
| |
| for (i = 0; i < XVECLEN (x, 0); i++) |
| if (! combinable_i3pat (i3, &XVECEXP (x, 0, i), i2dest, i1dest, |
| i1_not_in_src, pi3dest_killed)) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| /* Return 1 if X is an arithmetic expression that contains a multiplication |
| and division. We don't count multiplications by powers of two here. */ |
| |
| static int |
| contains_muldiv (rtx x) |
| { |
| switch (GET_CODE (x)) |
| { |
| case MOD: case DIV: case UMOD: case UDIV: |
| return 1; |
| |
| case MULT: |
| return ! (GET_CODE (XEXP (x, 1)) == CONST_INT |
| && exact_log2 (INTVAL (XEXP (x, 1))) >= 0); |
| default: |
| if (BINARY_P (x)) |
| return contains_muldiv (XEXP (x, 0)) |
| || contains_muldiv (XEXP (x, 1)); |
| |
| if (UNARY_P (x)) |
| return contains_muldiv (XEXP (x, 0)); |
| |
| return 0; |
| } |
| } |
| |
| /* Determine whether INSN can be used in a combination. Return nonzero if |
| not. This is used in try_combine to detect early some cases where we |
| can't perform combinations. */ |
| |
| static int |
| cant_combine_insn_p (rtx insn) |
| { |
| rtx set; |
| rtx src, dest; |
| |
| /* If this isn't really an insn, we can't do anything. |
| This can occur when flow deletes an insn that it has merged into an |
| auto-increment address. */ |
| if (! INSN_P (insn)) |
| return 1; |
| |
| /* Never combine loads and stores involving hard regs that are likely |
| to be spilled. The register allocator can usually handle such |
| reg-reg moves by tying. If we allow the combiner to make |
| substitutions of likely-spilled regs, we may abort in reload. |
| As an exception, we allow combinations involving fixed regs; these are |
| not available to the register allocator so there's no risk involved. */ |
| |
| set = single_set (insn); |
| if (! set) |
| return 0; |
| src = SET_SRC (set); |
| dest = SET_DEST (set); |
| if (GET_CODE (src) == SUBREG) |
| src = SUBREG_REG (src); |
| if (GET_CODE (dest) == SUBREG) |
| dest = SUBREG_REG (dest); |
| if (REG_P (src) && REG_P (dest) |
| && ((REGNO (src) < FIRST_PSEUDO_REGISTER |
| && ! fixed_regs[REGNO (src)] |
| && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (src)))) |
| || (REGNO (dest) < FIRST_PSEUDO_REGISTER |
| && ! fixed_regs[REGNO (dest)] |
| && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (dest)))))) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* Adjust INSN after we made a change to its destination. |
| |
| Changing the destination can invalidate notes that say something about |
| the results of the insn and a LOG_LINK pointing to the insn. */ |
| |
| static void |
| adjust_for_new_dest (rtx insn) |
| { |
| rtx *loc; |
| |
| /* For notes, be conservative and simply remove them. */ |
| loc = ®_NOTES (insn); |
| while (*loc) |
| { |
| enum reg_note kind = REG_NOTE_KIND (*loc); |
| if (kind == REG_EQUAL || kind == REG_EQUIV) |
| *loc = XEXP (*loc, 1); |
| else |
| loc = &XEXP (*loc, 1); |
| } |
| |
| /* The new insn will have a destination that was previously the destination |
| of an insn just above it. Call distribute_links to make a LOG_LINK from |
| the next use of that destination. */ |
| distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX)); |
| } |
| |
| /* Try to combine the insns I1 and I2 into I3. |
| Here I1 and I2 appear earlier than I3. |
| I1 can be zero; then we combine just I2 into I3. |
| |
| If we are combining three insns and the resulting insn is not recognized, |
| try splitting it into two insns. If that happens, I2 and I3 are retained |
| and I1 is pseudo-deleted by turning it into a NOTE. Otherwise, I1 and I2 |
| are pseudo-deleted. |
| |
| Return 0 if the combination does not work. Then nothing is changed. |
| If we did the combination, return the insn at which combine should |
| resume scanning. |
| |
| Set NEW_DIRECT_JUMP_P to a nonzero value if try_combine creates a |
| new direct jump instruction. */ |
| |
| static rtx |
| try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) |
| { |
| /* New patterns for I3 and I2, respectively. */ |
| rtx newpat, newi2pat = 0; |
| int substed_i2 = 0, substed_i1 = 0; |
| /* Indicates need to preserve SET in I1 or I2 in I3 if it is not dead. */ |
| int added_sets_1, added_sets_2; |
| /* Total number of SETs to put into I3. */ |
| int total_sets; |
| /* Nonzero if I2's body now appears in I3. */ |
| int i2_is_used; |
| /* INSN_CODEs for new I3, new I2, and user of condition code. */ |
| int insn_code_number, i2_code_number = 0, other_code_number = 0; |
| /* Contains I3 if the destination of I3 is used in its source, which means |
| that the old life of I3 is being killed. If that usage is placed into |
| I2 and not in I3, a REG_DEAD note must be made. */ |
| rtx i3dest_killed = 0; |
| /* SET_DEST and SET_SRC of I2 and I1. */ |
| rtx i2dest, i2src, i1dest = 0, i1src = 0; |
| /* PATTERN (I2), or a copy of it in certain cases. */ |
| rtx i2pat; |
| /* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC. */ |
| int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0; |
| int i1_feeds_i3 = 0; |
| /* Notes that must be added to REG_NOTES in I3 and I2. */ |
| rtx new_i3_notes, new_i2_notes; |
| /* Notes that we substituted I3 into I2 instead of the normal case. */ |
| int i3_subst_into_i2 = 0; |
| /* Notes that I1, I2 or I3 is a MULT operation. */ |
| int have_mult = 0; |
| int swap_i2i3 = 0; |
| |
| int maxreg; |
| rtx temp; |
| rtx link; |
| int i; |
| |
| /* Exit early if one of the insns involved can't be used for |
| combinations. */ |
| if (cant_combine_insn_p (i3) |
| || cant_combine_insn_p (i2) |
| || (i1 && cant_combine_insn_p (i1)) |
| /* We also can't do anything if I3 has a |
| REG_LIBCALL note since we don't want to disrupt the contiguity of a |
| libcall. */ |
| #if 0 |
| /* ??? This gives worse code, and appears to be unnecessary, since no |
| pass after flow uses REG_LIBCALL/REG_RETVAL notes. */ |
| || find_reg_note (i3, REG_LIBCALL, NULL_RTX) |
| #endif |
| ) |
| return 0; |
| |
| combine_attempts++; |
| undobuf.other_insn = 0; |
| |
| /* Reset the hard register usage information. */ |
| CLEAR_HARD_REG_SET (newpat_used_regs); |
| |
| /* If I1 and I2 both feed I3, they can be in any order. To simplify the |
| code below, set I1 to be the earlier of the two insns. */ |
| if (i1 && INSN_CUID (i1) > INSN_CUID (i2)) |
| temp = i1, i1 = i2, i2 = temp; |
| |
| added_links_insn = 0; |
| |
| /* First check for one important special-case that the code below will |
| not handle. Namely, the case where I1 is zero, I2 is a PARALLEL |
| and I3 is a SET whose SET_SRC is a SET_DEST in I2. In that case, |
| we may be able to replace that destination with the destination of I3. |
| This occurs in the common code where we compute both a quotient and |
| remainder into a structure, in which case we want to do the computation |
| directly into the structure to avoid register-register copies. |
| |
| Note that this case handles both multiple sets in I2 and also |
| cases where I2 has a number of CLOBBER or PARALLELs. |
| |
| We make very conservative checks below and only try to handle the |
| most common cases of this. For example, we only handle the case |
| where I2 and I3 are adjacent to avoid making difficult register |
| usage tests. */ |
| |
| if (i1 == 0 && NONJUMP_INSN_P (i3) && GET_CODE (PATTERN (i3)) == SET |
| && REG_P (SET_SRC (PATTERN (i3))) |
| && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER |
| && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3))) |
| && GET_CODE (PATTERN (i2)) == PARALLEL |
| && ! side_effects_p (SET_DEST (PATTERN (i3))) |
| /* If the dest of I3 is a ZERO_EXTRACT or STRICT_LOW_PART, the code |
| below would need to check what is inside (and reg_overlap_mentioned_p |
| doesn't support those codes anyway). Don't allow those destinations; |
| the resulting insn isn't likely to be recognized anyway. */ |
| && GET_CODE (SET_DEST (PATTERN (i3))) != ZERO_EXTRACT |
| && GET_CODE (SET_DEST (PATTERN (i3))) != STRICT_LOW_PART |
| && ! reg_overlap_mentioned_p (SET_SRC (PATTERN (i3)), |
| SET_DEST (PATTERN (i3))) |
| && next_real_insn (i2) == i3) |
| { |
| rtx p2 = PATTERN (i2); |
| |
| /* Make sure that the destination of I3, |
| which we are going to substitute into one output of I2, |
| is not used within another output of I2. We must avoid making this: |
| (parallel [(set (mem (reg 69)) ...) |
| (set (reg 69) ...)]) |
| which is not well-defined as to order of actions. |
| (Besides, reload can't handle output reloads for this.) |
| |
| The problem can also happen if the dest of I3 is a memory ref, |
| if another dest in I2 is an indirect memory ref. */ |
| for (i = 0; i < XVECLEN (p2, 0); i++) |
| if ((GET_CODE (XVECEXP (p2, 0, i)) == SET |
| || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER) |
| && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)), |
| SET_DEST (XVECEXP (p2, 0, i)))) |
| break; |
| |
| if (i == XVECLEN (p2, 0)) |
| for (i = 0; i < XVECLEN (p2, 0); i++) |
| if ((GET_CODE (XVECEXP (p2, 0, i)) == SET |
| || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER) |
| && SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3))) |
| { |
| combine_merges++; |
| |
| subst_insn = i3; |
| subst_low_cuid = INSN_CUID (i2); |
| |
| added_sets_2 = added_sets_1 = 0; |
| i2dest = SET_SRC (PATTERN (i3)); |
| |
| /* Replace the dest in I2 with our dest and make the resulting |
| insn the new pattern for I3. Then skip to where we |
| validate the pattern. Everything was set up above. */ |
| SUBST (SET_DEST (XVECEXP (p2, 0, i)), |
| SET_DEST (PATTERN (i3))); |
| |
| newpat = p2; |
| i3_subst_into_i2 = 1; |
| goto validate_replacement; |
| } |
| } |
| |
| /* If I2 is setting a double-word pseudo to a constant and I3 is setting |
| one of those words to another constant, merge them by making a new |
| constant. */ |
| if (i1 == 0 |
| && (temp = single_set (i2)) != 0 |
| && (GET_CODE (SET_SRC (temp)) == CONST_INT |
| || GET_CODE (SET_SRC (temp)) == CONST_DOUBLE) |
| && REG_P (SET_DEST (temp)) |
| && GET_MODE_CLASS (GET_MODE (SET_DEST (temp))) == MODE_INT |
| && GET_MODE_SIZE (GET_MODE (SET_DEST (temp))) == 2 * UNITS_PER_WORD |
| && GET_CODE (PATTERN (i3)) == SET |
| && GET_CODE (SET_DEST (PATTERN (i3))) == SUBREG |
| && SUBREG_REG (SET_DEST (PATTERN (i3))) == SET_DEST (temp) |
| && GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (i3)))) == MODE_INT |
| && GET_MODE_SIZE (GET_MODE (SET_DEST (PATTERN (i3)))) == UNITS_PER_WORD |
| && GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT) |
| { |
| HOST_WIDE_INT lo, hi; |
| |
| if (GET_CODE (SET_SRC (temp)) == CONST_INT) |
| lo = INTVAL (SET_SRC (temp)), hi = lo < 0 ? -1 : 0; |
| else |
| { |
| lo = CONST_DOUBLE_LOW (SET_SRC (temp)); |
| hi = CONST_DOUBLE_HIGH (SET_SRC (temp)); |
| } |
| |
| if (subreg_lowpart_p (SET_DEST (PATTERN (i3)))) |
| { |
| /* We don't handle the case of the target word being wider |
| than a host wide int. */ |
| gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD); |
| |
| lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1); |
| lo |= (INTVAL (SET_SRC (PATTERN (i3))) |
| & (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1)); |
| } |
| else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) |
| hi = INTVAL (SET_SRC (PATTERN (i3))); |
| else if (HOST_BITS_PER_WIDE_INT >= 2 * BITS_PER_WORD) |
| { |
| int sign = -(int) ((unsigned HOST_WIDE_INT) lo |
| >> (HOST_BITS_PER_WIDE_INT - 1)); |
| |
| lo &= ~ (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD |
| (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1)); |
| lo |= (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD |
| (INTVAL (SET_SRC (PATTERN (i3))))); |
| if (hi == sign) |
| hi = lo < 0 ? -1 : 0; |
| } |
| else |
| /* We don't handle the case of the higher word not fitting |
| entirely in either hi or lo. */ |
| gcc_unreachable (); |
| |
| combine_merges++; |
| subst_insn = i3; |
| subst_low_cuid = INSN_CUID (i2); |
| added_sets_2 = added_sets_1 = 0; |
| i2dest = SET_DEST (temp); |
| |
| SUBST (SET_SRC (temp), |
| immed_double_const (lo, hi, GET_MODE (SET_DEST (temp)))); |
| |
| newpat = PATTERN (i2); |
| goto validate_replacement; |
| } |
| |
| #ifndef HAVE_cc0 |
| /* If we have no I1 and I2 looks like: |
| (parallel [(set (reg:CC X) (compare:CC OP (const_int 0))) |
| (set Y OP)]) |
| make up a dummy I1 that is |
| (set Y OP) |
| and change I2 to be |
| (set (reg:CC X) (compare:CC Y (const_int 0))) |
| |
| (We can ignore any trailing CLOBBERs.) |
| |
| This undoes a previous combination and allows us to match a branch-and- |
| decrement insn. */ |
| |
| if (i1 == 0 && GET_CODE (PATTERN (i2)) == PARALLEL |
| && XVECLEN (PATTERN (i2), 0) >= 2 |
| && GET_CODE (XVECEXP (PATTERN (i2), 0, 0)) == SET |
| && (GET_MODE_CLASS (GET_MODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)))) |
| == MODE_CC) |
| && GET_CODE (SET_SRC (XVECEXP (PATTERN (i2), 0, 0))) == COMPARE |
| && XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 1) == const0_rtx |
| && GET_CODE (XVECEXP (PATTERN (i2), 0, 1)) == SET |
| && REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, 1))) |
| && rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 0), |
| SET_SRC (XVECEXP (PATTERN (i2), 0, 1)))) |
| { |
| for (i = XVECLEN (PATTERN (i2), 0) - 1; i >= 2; i--) |
| if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != CLOBBER) |
| break; |
| |
| if (i == 1) |
| { |
| /* We make I1 with the same INSN_UID as I2. This gives it |
| the same INSN_CUID for value tracking. Our fake I1 will |
| never appear in the insn stream so giving it the same INSN_UID |
| as I2 will not cause a problem. */ |
| |
| i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2, |
| BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2), |
| XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX, |
| NULL_RTX); |
| |
| SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0)); |
| SUBST (XEXP (SET_SRC (PATTERN (i2)), 0), |
| SET_DEST (PATTERN (i1))); |
| } |
| } |
| #endif |
| |
| /* Verify that I2 and I1 are valid for combining. */ |
| if (! can_combine_p (i2, i3, i1, NULL_RTX, &i2dest, &i2src) |
| || (i1 && ! can_combine_p (i1, i3, NULL_RTX, i2, &i1dest, &i1src))) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| /* Record whether I2DEST is used in I2SRC and similarly for the other |
| cases. Knowing this will help in register status updating below. */ |
| i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src); |
| i1dest_in_i1src = i1 && reg_overlap_mentioned_p (i1dest, i1src); |
| i2dest_in_i1src = i1 && reg_overlap_mentioned_p (i2dest, i1src); |
| |
| /* See if I1 directly feeds into I3. It does if I1DEST is not used |
| in I2SRC. */ |
| i1_feeds_i3 = i1 && ! reg_overlap_mentioned_p (i1dest, i2src); |
| |
| /* Ensure that I3's pattern can be the destination of combines. */ |
| if (! combinable_i3pat (i3, &PATTERN (i3), i2dest, i1dest, |
| i1 && i2dest_in_i1src && i1_feeds_i3, |
| &i3dest_killed)) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| /* See if any of the insns is a MULT operation. Unless one is, we will |
| reject a combination that is, since it must be slower. Be conservative |
| here. */ |
| if (GET_CODE (i2src) == MULT |
| || (i1 != 0 && GET_CODE (i1src) == MULT) |
| || (GET_CODE (PATTERN (i3)) == SET |
| && GET_CODE (SET_SRC (PATTERN (i3))) == MULT)) |
| have_mult = 1; |
| |
| /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd. |
| We used to do this EXCEPT in one case: I3 has a post-inc in an |
| output operand. However, that exception can give rise to insns like |
| mov r3,(r3)+ |
| which is a famous insn on the PDP-11 where the value of r3 used as the |
| source was model-dependent. Avoid this sort of thing. */ |
| |
| #if 0 |
| if (!(GET_CODE (PATTERN (i3)) == SET |
| && REG_P (SET_SRC (PATTERN (i3))) |
| && MEM_P (SET_DEST (PATTERN (i3))) |
| && (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC |
| || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC))) |
| /* It's not the exception. */ |
| #endif |
| #ifdef AUTO_INC_DEC |
| for (link = REG_NOTES (i3); link; link = XEXP (link, 1)) |
| if (REG_NOTE_KIND (link) == REG_INC |
| && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2)) |
| || (i1 != 0 |
| && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1))))) |
| { |
| undo_all (); |
| return 0; |
| } |
| #endif |
| |
| /* See if the SETs in I1 or I2 need to be kept around in the merged |
| instruction: whenever the value set there is still needed past I3. |
| For the SETs in I2, this is easy: we see if I2DEST dies or is set in I3. |
| |
| For the SET in I1, we have two cases: If I1 and I2 independently |
| feed into I3, the set in I1 needs to be kept around if I1DEST dies |
| or is set in I3. Otherwise (if I1 feeds I2 which feeds I3), the set |
| in I1 needs to be kept around unless I1DEST dies or is set in either |
| I2 or I3. We can distinguish these cases by seeing if I2SRC mentions |
| I1DEST. If so, we know I1 feeds into I2. */ |
| |
| added_sets_2 = ! dead_or_set_p (i3, i2dest); |
| |
| added_sets_1 |
| = i1 && ! (i1_feeds_i3 ? dead_or_set_p (i3, i1dest) |
| : (dead_or_set_p (i3, i1dest) || dead_or_set_p (i2, i1dest))); |
| |
| /* If the set in I2 needs to be kept around, we must make a copy of |
| PATTERN (I2), so that when we substitute I1SRC for I1DEST in |
| PATTERN (I2), we are only substituting for the original I1DEST, not into |
| an already-substituted copy. This also prevents making self-referential |
| rtx. If I2 is a PARALLEL, we just need the piece that assigns I2SRC to |
| I2DEST. */ |
| |
| i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL |
| ? gen_rtx_SET (VOIDmode, i2dest, i2src) |
| : PATTERN (i2)); |
| |
| if (added_sets_2) |
| i2pat = copy_rtx (i2pat); |
| |
| combine_merges++; |
| |
| /* Substitute in the latest insn for the regs set by the earlier ones. */ |
| |
| maxreg = max_reg_num (); |
| |
| subst_insn = i3; |
| |
| /* It is possible that the source of I2 or I1 may be performing an |
| unneeded operation, such as a ZERO_EXTEND of something that is known |
| to have the high part zero. Handle that case by letting subst look at |
| the innermost one of them. |
| |
| Another way to do this would be to have a function that tries to |
| simplify a single insn instead of merging two or more insns. We don't |
| do this because of the potential of infinite loops and because |
| of the potential extra memory required. However, doing it the way |
| we are is a bit of a kludge and doesn't catch all cases. |
| |
| But only do this if -fexpensive-optimizations since it slows things down |
| and doesn't usually win. */ |
| |
| if (flag_expensive_optimizations) |
| { |
| /* Pass pc_rtx so no substitutions are done, just simplifications. */ |
| if (i1) |
| { |
| subst_low_cuid = INSN_CUID (i1); |
| i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0); |
| } |
| else |
| { |
| subst_low_cuid = INSN_CUID (i2); |
| i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0); |
| } |
| } |
| |
| #ifndef HAVE_cc0 |
| /* Many machines that don't use CC0 have insns that can both perform an |
| arithmetic operation and set the condition code. These operations will |
| be represented as a PARALLEL with the first element of the vector |
| being a COMPARE of an arithmetic operation with the constant zero. |
| The second element of the vector will set some pseudo to the result |
| of the same arithmetic operation. If we simplify the COMPARE, we won't |
| match such a pattern and so will generate an extra insn. Here we test |
| for this case, where both the comparison and the operation result are |
| needed, and make the PARALLEL by just replacing I2DEST in I3SRC with |
| I2SRC. Later we will make the PARALLEL that contains I2. */ |
| |
| if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET |
| && GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE |
| && XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx |
| && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest)) |
| { |
| #ifdef SELECT_CC_MODE |
| rtx *cc_use; |
| enum machine_mode compare_mode; |
| #endif |
| |
| newpat = PATTERN (i3); |
| SUBST (XEXP (SET_SRC (newpat), 0), i2src); |
| |
| i2_is_used = 1; |
| |
| #ifdef SELECT_CC_MODE |
| /* See if a COMPARE with the operand we substituted in should be done |
| with the mode that is currently being used. If not, do the same |
| processing we do in `subst' for a SET; namely, if the destination |
| is used only once, try to replace it with a register of the proper |
| mode and also replace the COMPARE. */ |
| if (undobuf.other_insn == 0 |
| && (cc_use = find_single_use (SET_DEST (newpat), i3, |
| &undobuf.other_insn)) |
| && ((compare_mode = SELECT_CC_MODE (GET_CODE (*cc_use), |
| i2src, const0_rtx)) |
| != GET_MODE (SET_DEST (newpat)))) |
| { |
| unsigned int regno = REGNO (SET_DEST (newpat)); |
| rtx new_dest = gen_rtx_REG (compare_mode, regno); |
| |
| if (regno < FIRST_PSEUDO_REGISTER |
| || (REG_N_SETS (regno) == 1 && ! added_sets_2 |
| && ! REG_USERVAR_P (SET_DEST (newpat)))) |
| { |
| if (regno >= FIRST_PSEUDO_REGISTER) |
| SUBST (regno_reg_rtx[regno], new_dest); |
| |
| SUBST (SET_DEST (newpat), new_dest); |
| SUBST (XEXP (*cc_use, 0), new_dest); |
| SUBST (SET_SRC (newpat), |
| gen_rtx_COMPARE (compare_mode, i2src, const0_rtx)); |
| } |
| else |
| undobuf.other_insn = 0; |
| } |
| #endif |
| } |
| else |
| #endif |
| { |
| n_occurrences = 0; /* `subst' counts here */ |
| |
| /* If I1 feeds into I2 (not into I3) and I1DEST is in I1SRC, we |
| need to make a unique copy of I2SRC each time we substitute it |
| to avoid self-referential rtl. */ |
| |
| subst_low_cuid = INSN_CUID (i2); |
| newpat = subst (PATTERN (i3), i2dest, i2src, 0, |
| ! i1_feeds_i3 && i1dest_in_i1src); |
| substed_i2 = 1; |
| |
| /* Record whether i2's body now appears within i3's body. */ |
| i2_is_used = n_occurrences; |
| } |
| |
| /* If we already got a failure, don't try to do more. Otherwise, |
| try to substitute in I1 if we have it. */ |
| |
| if (i1 && GET_CODE (newpat) != CLOBBER) |
| { |
| /* Before we can do this substitution, we must redo the test done |
| above (see detailed comments there) that ensures that I1DEST |
| isn't mentioned in any SETs in NEWPAT that are field assignments. */ |
| |
| if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, |
| 0, (rtx*) 0)) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| n_occurrences = 0; |
| subst_low_cuid = INSN_CUID (i1); |
| newpat = subst (newpat, i1dest, i1src, 0, 0); |
| substed_i1 = 1; |
| } |
| |
| /* Fail if an autoincrement side-effect has been duplicated. Be careful |
| to count all the ways that I2SRC and I1SRC can be used. */ |
| if ((FIND_REG_INC_NOTE (i2, NULL_RTX) != 0 |
| && i2_is_used + added_sets_2 > 1) |
| || (i1 != 0 && FIND_REG_INC_NOTE (i1, NULL_RTX) != 0 |
| && (n_occurrences + added_sets_1 + (added_sets_2 && ! i1_feeds_i3) |
| > 1)) |
| /* Fail if we tried to make a new register (we used to abort, but there's |
| really no reason to). */ |
| || max_reg_num () != maxreg |
| /* Fail if we couldn't do something and have a CLOBBER. */ |
| || GET_CODE (newpat) == CLOBBER |
| /* Fail if this new pattern is a MULT and we didn't have one before |
| at the outer level. */ |
| || (GET_CODE (newpat) == SET && GET_CODE (SET_SRC (newpat)) == MULT |
| && ! have_mult)) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| /* If the actions of the earlier insns must be kept |
| in addition to substituting them into the latest one, |
| we must make a new PARALLEL for the latest insn |
| to hold additional the SETs. */ |
| |
| if (added_sets_1 || added_sets_2) |
| { |
| combine_extras++; |
| |
| if (GET_CODE (newpat) == PARALLEL) |
| { |
| rtvec old = XVEC (newpat, 0); |
| total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2; |
| newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets)); |
| memcpy (XVEC (newpat, 0)->elem, &old->elem[0], |
| sizeof (old->elem[0]) * old->num_elem); |
| } |
| else |
| { |
| rtx old = newpat; |
| total_sets = 1 + added_sets_1 + added_sets_2; |
| newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets)); |
| XVECEXP (newpat, 0, 0) = old; |
| } |
| |
| if (added_sets_1) |
| XVECEXP (newpat, 0, --total_sets) |
| = (GET_CODE (PATTERN (i1)) == PARALLEL |
| ? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1)); |
| |
| if (added_sets_2) |
| { |
| /* If there is no I1, use I2's body as is. We used to also not do |
| the subst call below if I2 was substituted into I3, |
| but that could lose a simplification. */ |
| if (i1 == 0) |
| XVECEXP (newpat, 0, --total_sets) = i2pat; |
| else |
| /* See comment where i2pat is assigned. */ |
| XVECEXP (newpat, 0, --total_sets) |
| = subst (i2pat, i1dest, i1src, 0, 0); |
| } |
| } |
| |
| /* We come here when we are replacing a destination in I2 with the |
| destination of I3. */ |
| validate_replacement: |
| |
| /* Note which hard regs this insn has as inputs. */ |
| mark_used_regs_combine (newpat); |
| |
| /* Is the result of combination a valid instruction? */ |
| insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); |
| |
| /* If the result isn't valid, see if it is a PARALLEL of two SETs where |
| the second SET's destination is a register that is unused and isn't |
| marked as an instruction that might trap in an EH region. In that case, |
| we just need the first SET. This can occur when simplifying a divmod |
| insn. We *must* test for this case here because the code below that |
| splits two independent SETs doesn't handle this case correctly when it |
| updates the register status. |
| |
| It's pointless doing this if we originally had two sets, one from |
| i3, and one from i2. Combining then splitting the parallel results |
| in the original i2 again plus an invalid insn (which we delete). |
| The net effect is only to move instructions around, which makes |
| debug info less accurate. |
| |
| Also check the case where the first SET's destination is unused. |
| That would not cause incorrect code, but does cause an unneeded |
| insn to remain. */ |
| |
| if (insn_code_number < 0 |
| && !(added_sets_2 && i1 == 0) |
| && GET_CODE (newpat) == PARALLEL |
| && XVECLEN (newpat, 0) == 2 |
| && GET_CODE (XVECEXP (newpat, 0, 0)) == SET |
| && GET_CODE (XVECEXP (newpat, 0, 1)) == SET |
| && asm_noperands (newpat) < 0) |
| { |
| rtx set0 = XVECEXP (newpat, 0, 0); |
| rtx set1 = XVECEXP (newpat, 0, 1); |
| rtx note; |
| |
| if (((REG_P (SET_DEST (set1)) |
| && find_reg_note (i3, REG_UNUSED, SET_DEST (set1))) |
| || (GET_CODE (SET_DEST (set1)) == SUBREG |
| && find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1))))) |
| && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX)) |
| || INTVAL (XEXP (note, 0)) <= 0) |
| && ! side_effects_p (SET_SRC (set1))) |
| { |
| newpat = set0; |
| insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); |
| } |
| |
| else if (((REG_P (SET_DEST (set0)) |
| && find_reg_note (i3, REG_UNUSED, SET_DEST (set0))) |
| || (GET_CODE (SET_DEST (set0)) == SUBREG |
| && find_reg_note (i3, REG_UNUSED, |
| SUBREG_REG (SET_DEST (set0))))) |
| && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX)) |
| || INTVAL (XEXP (note, 0)) <= 0) |
| && ! side_effects_p (SET_SRC (set0))) |
| { |
| newpat = set1; |
| insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); |
| |
| if (insn_code_number >= 0) |
| { |
| /* If we will be able to accept this, we have made a |
| change to the destination of I3. This requires us to |
| do a few adjustments. */ |
| |
| PATTERN (i3) = newpat; |
| adjust_for_new_dest (i3); |
| } |
| } |
| } |
| |
| /* If we were combining three insns and the result is a simple SET |
| with no ASM_OPERANDS that wasn't recognized, try to split it into two |
| insns. There are two ways to do this. It can be split using a |
| machine-specific method (like when you have an addition of a large |
| constant) or by combine in the function find_split_point. */ |
| |
| if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET |
| && asm_noperands (newpat) < 0) |
| { |
| rtx m_split, *split; |
| rtx ni2dest = i2dest; |
| |
| /* See if the MD file can split NEWPAT. If it can't, see if letting it |
| use I2DEST as a scratch register will help. In the latter case, |
| convert I2DEST to the mode of the source of NEWPAT if we can. */ |
| |
| m_split = split_insns (newpat, i3); |
| |
| /* We can only use I2DEST as a scratch reg if it doesn't overlap any |
| inputs of NEWPAT. */ |
| |
| /* ??? If I2DEST is not safe, and I1DEST exists, then it would be |
| possible to try that as a scratch reg. This would require adding |
| more code to make it work though. */ |
| |
| if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat)) |
| { |
| /* If I2DEST is a hard register or the only use of a pseudo, |
| we can change its mode. */ |
| if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest) |
| && GET_MODE (SET_DEST (newpat)) != VOIDmode |
| && REG_P (i2dest) |
| && (REGNO (i2dest) < FIRST_PSEUDO_REGISTER |
| || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2 |
| && ! REG_USERVAR_P (i2dest)))) |
| ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)), |
| REGNO (i2dest)); |
| |
| m_split = split_insns (gen_rtx_PARALLEL |
| (VOIDmode, |
| gen_rtvec (2, newpat, |
| gen_rtx_CLOBBER (VOIDmode, |
| ni2dest))), |
| i3); |
| /* If the split with the mode-changed register didn't work, try |
| the original register. */ |
| if (! m_split && ni2dest != i2dest) |
| { |
| ni2dest = i2dest; |
| m_split = split_insns (gen_rtx_PARALLEL |
| (VOIDmode, |
| gen_rtvec (2, newpat, |
| gen_rtx_CLOBBER (VOIDmode, |
| i2dest))), |
| i3); |
| } |
| } |
| |
| if (m_split && NEXT_INSN (m_split) == NULL_RTX) |
| { |
| m_split = PATTERN (m_split); |
| insn_code_number = recog_for_combine (&m_split, i3, &new_i3_notes); |
| if (insn_code_number >= 0) |
| newpat = m_split; |
| } |
| else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX |
| && (next_real_insn (i2) == i3 |
| || ! use_crosses_set_p (PATTERN (m_split), INSN_CUID (i2)))) |
| { |
| rtx i2set, i3set; |
| rtx newi3pat = PATTERN (NEXT_INSN (m_split)); |
| newi2pat = PATTERN (m_split); |
| |
| i3set = single_set (NEXT_INSN (m_split)); |
| i2set = single_set (m_split); |
| |
| /* In case we changed the mode of I2DEST, replace it in the |
| pseudo-register table here. We can't do it above in case this |
| code doesn't get executed and we do a split the other way. */ |
| |
| if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) |
| SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest); |
| |
| i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); |
| |
| /* If I2 or I3 has multiple SETs, we won't know how to track |
| register status, so don't use these insns. If I2's destination |
| is used between I2 and I3, we also can't use these insns. */ |
| |
| if (i2_code_number >= 0 && i2set && i3set |
| && (next_real_insn (i2) == i3 |
| || ! reg_used_between_p (SET_DEST (i2set), i2, i3))) |
| insn_code_number = recog_for_combine (&newi3pat, i3, |
| &new_i3_notes); |
| if (insn_code_number >= 0) |
| newpat = newi3pat; |
| |
| /* It is possible that both insns now set the destination of I3. |
| If so, we must show an extra use of it. */ |
| |
| if (insn_code_number >= 0) |
| { |
| rtx new_i3_dest = SET_DEST (i3set); |
| rtx new_i2_dest = SET_DEST (i2set); |
| |
| while (GET_CODE (new_i3_dest) == ZERO_EXTRACT |
| || GET_CODE (new_i3_dest) == STRICT_LOW_PART |
| || GET_CODE (new_i3_dest) == SUBREG) |
| new_i3_dest = XEXP (new_i3_dest, 0); |
| |
| while (GET_CODE (new_i2_dest) == ZERO_EXTRACT |
| || GET_CODE (new_i2_dest) == STRICT_LOW_PART |
| || GET_CODE (new_i2_dest) == SUBREG) |
| new_i2_dest = XEXP (new_i2_dest, 0); |
| |
| if (REG_P (new_i3_dest) |
| && REG_P (new_i2_dest) |
| && REGNO (new_i3_dest) == REGNO (new_i2_dest)) |
| REG_N_SETS (REGNO (new_i2_dest))++; |
| } |
| } |
| |
| /* If we can split it and use I2DEST, go ahead and see if that |
| helps things be recognized. Verify that none of the registers |
| are set between I2 and I3. */ |
| if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0 |
| #ifdef HAVE_cc0 |
| && REG_P (i2dest) |
| #endif |
| /* We need I2DEST in the proper mode. If it is a hard register |
| or the only use of a pseudo, we can change its mode. */ |
| && (GET_MODE (*split) == GET_MODE (i2dest) |
| || GET_MODE (*split) == VOIDmode |
| || REGNO (i2dest) < FIRST_PSEUDO_REGISTER |
| || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2 |
| && ! REG_USERVAR_P (i2dest))) |
| && (next_real_insn (i2) == i3 |
| || ! use_crosses_set_p (*split, INSN_CUID (i2))) |
| /* We can't overwrite I2DEST if its value is still used by |
| NEWPAT. */ |
| && ! reg_referenced_p (i2dest, newpat)) |
| { |
| rtx newdest = i2dest; |
| enum rtx_code split_code = GET_CODE (*split); |
| enum machine_mode split_mode = GET_MODE (*split); |
| |
| /* Get NEWDEST as a register in the proper mode. We have already |
| validated that we can do this. */ |
| if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode) |
| { |
| newdest = gen_rtx_REG (split_mode, REGNO (i2dest)); |
| |
| if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) |
| SUBST (regno_reg_rtx[REGNO (i2dest)], newdest); |
| } |
| |
| /* If *SPLIT is a (mult FOO (const_int pow2)), convert it to |
| an ASHIFT. This can occur if it was inside a PLUS and hence |
| appeared to be a memory address. This is a kludge. */ |
| if (split_code == MULT |
| && GET_CODE (XEXP (*split, 1)) == CONST_INT |
| && INTVAL (XEXP (*split, 1)) > 0 |
| && (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0) |
| { |
| SUBST (*split, gen_rtx_ASHIFT (split_mode, |
| XEXP (*split, 0), GEN_INT (i))); |
| /* Update split_code because we may not have a multiply |
| anymore. */ |
| split_code = GET_CODE (*split); |
| } |
| |
| #ifdef INSN_SCHEDULING |
| /* If *SPLIT is a paradoxical SUBREG, when we split it, it should |
| be written as a ZERO_EXTEND. */ |
| if (split_code == SUBREG && MEM_P (SUBREG_REG (*split))) |
| { |
| #ifdef LOAD_EXTEND_OP |
| /* Or as a SIGN_EXTEND if LOAD_EXTEND_OP says that that's |
| what it really is. */ |
| if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (*split))) |
| == SIGN_EXTEND) |
| SUBST (*split, gen_rtx_SIGN_EXTEND (split_mode, |
| SUBREG_REG (*split))); |
| else |
| #endif |
| SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode, |
| SUBREG_REG (*split))); |
| } |
| #endif |
| |
| newi2pat = gen_rtx_SET (VOIDmode, newdest, *split); |
| SUBST (*split, newdest); |
| i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); |
| |
| /* recog_for_combine might have added CLOBBERs to newi2pat. |
| Make sure NEWPAT does not depend on the clobbered regs. */ |
| if (GET_CODE (newi2pat) == PARALLEL) |
| for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--) |
| if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER) |
| { |
| rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0); |
| if (reg_overlap_mentioned_p (reg, newpat)) |
| { |
| undo_all (); |
| return 0; |
| } |
| } |
| |
| /* If the split point was a MULT and we didn't have one before, |
| don't use one now. */ |
| if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult)) |
| insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); |
| } |
| } |
| |
| /* Check for a case where we loaded from memory in a narrow mode and |
| then sign extended it, but we need both registers. In that case, |
| we have a PARALLEL with both loads from the same memory location. |
| We can split this into a load from memory followed by a register-register |
| copy. This saves at least one insn, more if register allocation can |
| eliminate the copy. |
| |
| We cannot do this if the destination of the first assignment is a |
| condition code register or cc0. We eliminate this case by making sure |
| the SET_DEST and SET_SRC have the same mode. |
| |
| We cannot do this if the destination of the second assignment is |
| a register that we have already assumed is zero-extended. Similarly |
| for a SUBREG of such a register. */ |
| |
| else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0 |
| && GET_CODE (newpat) == PARALLEL |
| && XVECLEN (newpat, 0) == 2 |
| && GET_CODE (XVECEXP (newpat, 0, 0)) == SET |
| && GET_CODE (SET_SRC (XVECEXP (newpat, 0, 0))) == SIGN_EXTEND |
| && (GET_MODE (SET_DEST (XVECEXP (newpat, 0, 0))) |
| == GET_MODE (SET_SRC (XVECEXP (newpat, 0, 0)))) |
| && GET_CODE (XVECEXP (newpat, 0, 1)) == SET |
| && rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)), |
| XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0)) |
| && ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)), |
| INSN_CUID (i2)) |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART |
| && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)), |
| (REG_P (temp) |
| && reg_stat[REGNO (temp)].nonzero_bits != 0 |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT |
| && (reg_stat[REGNO (temp)].nonzero_bits |
| != GET_MODE_MASK (word_mode)))) |
| && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG |
| && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))), |
| (REG_P (temp) |
| && reg_stat[REGNO (temp)].nonzero_bits != 0 |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT |
| && (reg_stat[REGNO (temp)].nonzero_bits |
| != GET_MODE_MASK (word_mode))))) |
| && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)), |
| SET_SRC (XVECEXP (newpat, 0, 1))) |
| && ! find_reg_note (i3, REG_UNUSED, |
| SET_DEST (XVECEXP (newpat, 0, 0)))) |
| { |
| rtx ni2dest; |
| |
| newi2pat = XVECEXP (newpat, 0, 0); |
| ni2dest = SET_DEST (XVECEXP (newpat, 0, 0)); |
| newpat = XVECEXP (newpat, 0, 1); |
| SUBST (SET_SRC (newpat), |
| gen_lowpart (GET_MODE (SET_SRC (newpat)), ni2dest)); |
| i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); |
| |
| if (i2_code_number >= 0) |
| insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); |
| |
| if (insn_code_number >= 0) |
| swap_i2i3 = 1; |
| } |
| |
| /* Similarly, check for a case where we have a PARALLEL of two independent |
| SETs but we started with three insns. In this case, we can do the sets |
| as two separate insns. This case occurs when some SET allows two |
| other insns to combine, but the destination of that SET is still live. */ |
| |
| else if (i1 && insn_code_number < 0 && asm_noperands (newpat) < 0 |
| && GET_CODE (newpat) == PARALLEL |
| && XVECLEN (newpat, 0) == 2 |
| && GET_CODE (XVECEXP (newpat, 0, 0)) == SET |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART |
| && GET_CODE (XVECEXP (newpat, 0, 1)) == SET |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART |
| && ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)), |
| INSN_CUID (i2)) |
| /* Don't pass sets with (USE (MEM ...)) dests to the following. */ |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != USE |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != USE |
| && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)), |
| XVECEXP (newpat, 0, 0)) |
| && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)), |
| XVECEXP (newpat, 0, 1)) |
| && ! (contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 0))) |
| && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1))))) |
| { |
| /* Normally, it doesn't matter which of the two is done first, |
| but it does if one references cc0. In that case, it has to |
| be first. */ |
| #ifdef HAVE_cc0 |
| if (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0))) |
| { |
| newi2pat = XVECEXP (newpat, 0, 0); |
| newpat = XVECEXP (newpat, 0, 1); |
| } |
| else |
| #endif |
| { |
| newi2pat = XVECEXP (newpat, 0, 1); |
| newpat = XVECEXP (newpat, 0, 0); |
| } |
| |
| i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); |
| |
| if (i2_code_number >= 0) |
| insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); |
| } |
| |
| /* If it still isn't recognized, fail and change things back the way they |
| were. */ |
| if ((insn_code_number < 0 |
| /* Is the result a reasonable ASM_OPERANDS? */ |
| && (! check_asm_operands (newpat) || added_sets_1 || added_sets_2))) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| /* If we had to change another insn, make sure it is valid also. */ |
| if (undobuf.other_insn) |
| { |
| rtx other_pat = PATTERN (undobuf.other_insn); |
| rtx new_other_notes; |
| rtx note, next; |
| |
| CLEAR_HARD_REG_SET (newpat_used_regs); |
| |
| other_code_number = recog_for_combine (&other_pat, undobuf.other_insn, |
| &new_other_notes); |
| |
| if (other_code_number < 0 && ! check_asm_operands (other_pat)) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| PATTERN (undobuf.other_insn) = other_pat; |
| |
| /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they |
| are still valid. Then add any non-duplicate notes added by |
| recog_for_combine. */ |
| for (note = REG_NOTES (undobuf.other_insn); note; note = next) |
| { |
| next = XEXP (note, 1); |
| |
| if (REG_NOTE_KIND (note) == REG_UNUSED |
| && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn))) |
| { |
| if (REG_P (XEXP (note, 0))) |
| REG_N_DEATHS (REGNO (XEXP (note, 0)))--; |
| |
| remove_note (undobuf.other_insn, note); |
| } |
| } |
| |
| for (note = new_other_notes; note; note = XEXP (note, 1)) |
| if (REG_P (XEXP (note, 0))) |
| REG_N_DEATHS (REGNO (XEXP (note, 0)))++; |
| |
| distribute_notes (new_other_notes, undobuf.other_insn, |
| undobuf.other_insn, NULL_RTX); |
| } |
| #ifdef HAVE_cc0 |
| /* If I2 is the CC0 setter and I3 is the CC0 user then check whether |
| they are adjacent to each other or not. */ |
| { |
| rtx p = prev_nonnote_insn (i3); |
| if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat |
| && sets_cc0_p (newi2pat)) |
| { |
| undo_all (); |
| return 0; |
| } |
| } |
| #endif |
| |
| /* Only allow this combination if insn_rtx_costs reports that the |
| replacement instructions are cheaper than the originals. */ |
| if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat)) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| /* We now know that we can do this combination. Merge the insns and |
| update the status of registers and LOG_LINKS. */ |
| |
| if (swap_i2i3) |
| { |
| rtx insn; |
| rtx link; |
| rtx ni2dest; |
| |
| /* I3 now uses what used to be its destination and which is now |
| I2's destination. This requires us to do a few adjustments. */ |
| PATTERN (i3) = newpat; |
| adjust_for_new_dest (i3); |
| |
| /* We need a LOG_LINK from I3 to I2. But we used to have one, |
| so we still will. |
| |
| However, some later insn might be using I2's dest and have |
| a LOG_LINK pointing at I3. We must remove this link. |
| The simplest way to remove the link is to point it at I1, |
| which we know will be a NOTE. */ |
| |
| /* newi2pat is usually a SET here; however, recog_for_combine might |
| have added some clobbers. */ |
| if (GET_CODE (newi2pat) == PARALLEL) |
| ni2dest = SET_DEST (XVECEXP (newi2pat, 0, 0)); |
| else |
| ni2dest = SET_DEST (newi2pat); |
| |
| for (insn = NEXT_INSN (i3); |
| insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR |
| || insn != BB_HEAD (this_basic_block->next_bb)); |
| insn = NEXT_INSN (insn)) |
| { |
| if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn))) |
| { |
| for (link = LOG_LINKS (insn); link; |
| link = XEXP (link, 1)) |
| if (XEXP (link, 0) == i3) |
| XEXP (link, 0) = i1; |
| |
| break; |
| } |
| } |
| } |
| |
| { |
| rtx i3notes, i2notes, i1notes = 0; |
| rtx i3links, i2links, i1links = 0; |
| rtx midnotes = 0; |
| unsigned int regno; |
| |
| /* Get the old REG_NOTES and LOG_LINKS from all our insns and |
| clear them. */ |
| i3notes = REG_NOTES (i3), i3links = LOG_LINKS (i3); |
| i2notes = REG_NOTES (i2), i2links = LOG_LINKS (i2); |
| if (i1) |
| i1notes = REG_NOTES (i1), i1links = LOG_LINKS (i1); |
| |
| /* Ensure that we do not have something that should not be shared but |
| occurs multiple times in the new insns. Check this by first |
| resetting all the `used' flags and then copying anything is shared. */ |
| |
| reset_used_flags (i3notes); |
| reset_used_flags (i2notes); |
| reset_used_flags (i1notes); |
| reset_used_flags (newpat); |
| reset_used_flags (newi2pat); |
| if (undobuf.other_insn) |
| reset_used_flags (PATTERN (undobuf.other_insn)); |
| |
| i3notes = copy_rtx_if_shared (i3notes); |
| i2notes = copy_rtx_if_shared (i2notes); |
| i1notes = copy_rtx_if_shared (i1notes); |
| newpat = copy_rtx_if_shared (newpat); |
| newi2pat = copy_rtx_if_shared (newi2pat); |
| if (undobuf.other_insn) |
| reset_used_flags (PATTERN (undobuf.other_insn)); |
| |
| INSN_CODE (i3) = insn_code_number; |
| PATTERN (i3) = newpat; |
| |
| if (CALL_P (i3) && CALL_INSN_FUNCTION_USAGE (i3)) |
| { |
| rtx call_usage = CALL_INSN_FUNCTION_USAGE (i3); |
| |
| reset_used_flags (call_usage); |
| call_usage = copy_rtx (call_usage); |
| |
| if (substed_i2) |
| replace_rtx (call_usage, i2dest, i2src); |
| |
| if (substed_i1) |
| replace_rtx (call_usage, i1dest, i1src); |
| |
| CALL_INSN_FUNCTION_USAGE (i3) = call_usage; |
| } |
| |
| if (undobuf.other_insn) |
| INSN_CODE (undobuf.other_insn) = other_code_number; |
| |
| /* We had one special case above where I2 had more than one set and |
| we replaced a destination of one of those sets with the destination |
| of I3. In that case, we have to update LOG_LINKS of insns later |
| in this basic block. Note that this (expensive) case is rare. |
| |
| Also, in this case, we must pretend that all REG_NOTEs for I2 |
| actually came from I3, so that REG_UNUSED notes from I2 will be |
| properly handled. */ |
| |
| if (i3_subst_into_i2) |
| { |
| for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++) |
| if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != USE |
| && REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) |
| && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest |
| && ! find_reg_note (i2, REG_UNUSED, |
| SET_DEST (XVECEXP (PATTERN (i2), 0, i)))) |
| for (temp = NEXT_INSN (i2); |
| temp && (this_basic_block->next_bb == EXIT_BLOCK_PTR |
| || BB_HEAD (this_basic_block) != temp); |
| temp = NEXT_INSN (temp)) |
| if (temp != i3 && INSN_P (temp)) |
| for (link = LOG_LINKS (temp); link; link = XEXP (link, 1)) |
| if (XEXP (link, 0) == i2) |
| XEXP (link, 0) = i3; |
| |
| if (i3notes) |
| { |
| rtx link = i3notes; |
| while (XEXP (link, 1)) |
| link = XEXP (link, 1); |
| XEXP (link, 1) = i2notes; |
| } |
| else |
| i3notes = i2notes; |
| i2notes = 0; |
| } |
| |
| LOG_LINKS (i3) = 0; |
| REG_NOTES (i3) = 0; |
| LOG_LINKS (i2) = 0; |
| REG_NOTES (i2) = 0; |
| |
| if (newi2pat) |
| { |
| INSN_CODE (i2) = i2_code_number; |
| PATTERN (i2) = newi2pat; |
| } |
| else |
| SET_INSN_DELETED (i2); |
| |
| if (i1) |
| { |
| LOG_LINKS (i1) = 0; |
| REG_NOTES (i1) = 0; |
| SET_INSN_DELETED (i1); |
| } |
| |
| /* Get death notes for everything that is now used in either I3 or |
| I2 and used to die in a previous insn. If we built two new |
| patterns, move from I1 to I2 then I2 to I3 so that we get the |
| proper movement on registers that I2 modifies. */ |
| |
| if (newi2pat) |
| { |
| move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes); |
| move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes); |
| } |
| else |
| move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2), |
| i3, &midnotes); |
| |
| /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */ |
| if (i3notes) |
| distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX); |
| if (i2notes) |
| distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX); |
| if (i1notes) |
| distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX); |
| if (midnotes) |
| distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX); |
| |
| /* Distribute any notes added to I2 or I3 by recog_for_combine. We |
| know these are REG_UNUSED and want them to go to the desired insn, |
| so we always pass it as i3. We have not counted the notes in |
| reg_n_deaths yet, so we need to do so now. */ |
| |
| if (newi2pat && new_i2_notes) |
| { |
| for (temp = new_i2_notes; temp; temp = XEXP (temp, 1)) |
| if (REG_P (XEXP (temp, 0))) |
| REG_N_DEATHS (REGNO (XEXP (temp, 0)))++; |
| |
| distribute_notes (new_i2_notes, i2, i2, NULL_RTX); |
| } |
| |
| if (new_i3_notes) |
| { |
| for (temp = new_i3_notes; temp; temp = XEXP (temp, 1)) |
| if (REG_P (XEXP (temp, 0))) |
| REG_N_DEATHS (REGNO (XEXP (temp, 0)))++; |
| |
| distribute_notes (new_i3_notes, i3, i3, NULL_RTX); |
| } |
| |
| /* If I3DEST was used in I3SRC, it really died in I3. We may need to |
| put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets |
| I3DEST, the death must be somewhere before I2, not I3. If we passed I3 |
| in that case, it might delete I2. Similarly for I2 and I1. |
| Show an additional death due to the REG_DEAD note we make here. If |
| we discard it in distribute_notes, we will decrement it again. */ |
| |
| if (i3dest_killed) |
| { |
| if (REG_P (i3dest_killed)) |
| REG_N_DEATHS (REGNO (i3dest_killed))++; |
| |
| if (newi2pat && reg_set_p (i3dest_killed, newi2pat)) |
| distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed, |
| NULL_RTX), |
| NULL_RTX, i2, NULL_RTX); |
| else |
| distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed, |
| NULL_RTX), |
| NULL_RTX, i3, newi2pat ? i2 : NULL_RTX); |
| } |
| |
| if (i2dest_in_i2src) |
| { |
| if (REG_P (i2dest)) |
| REG_N_DEATHS (REGNO (i2dest))++; |
| |
| if (newi2pat && reg_set_p (i2dest, newi2pat)) |
| distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX), |
| NULL_RTX, i2, NULL_RTX); |
| else |
| distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX), |
| NULL_RTX, i3, newi2pat ? i2 : NULL_RTX); |
| } |
| |
| if (i1dest_in_i1src) |
| { |
| if (REG_P (i1dest)) |
| REG_N_DEATHS (REGNO (i1dest))++; |
| |
| if (newi2pat && reg_set_p (i1dest, newi2pat)) |
| distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX), |
| NULL_RTX, i2, NULL_RTX); |
| else |
| distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX), |
| NULL_RTX, i3, newi2pat ? i2 : NULL_RTX); |
| } |
| |
| distribute_links (i3links); |
| distribute_links (i2links); |
| distribute_links (i1links); |
| |
| if (REG_P (i2dest)) |
| { |
| rtx link; |
| rtx i2_insn = 0, i2_val = 0, set; |
| |
| /* The insn that used to set this register doesn't exist, and |
| this life of the register may not exist either. See if one of |
| I3's links points to an insn that sets I2DEST. If it does, |
| that is now the last known value for I2DEST. If we don't update |
| this and I2 set the register to a value that depended on its old |
| contents, we will get confused. If this insn is used, thing |
| will be set correctly in combine_instructions. */ |
| |
| for (link = LOG_LINKS (i3); link; link = XEXP (link, 1)) |
| if ((set = single_set (XEXP (link, 0))) != 0 |
| && rtx_equal_p (i2dest, SET_DEST (set))) |
| i2_insn = XEXP (link, 0), i2_val = SET_SRC (set); |
| |
| record_value_for_reg (i2dest, i2_insn, i2_val); |
| |
| /* If the reg formerly set in I2 died only once and that was in I3, |
| zero its use count so it won't make `reload' do any work. */ |
| if (! added_sets_2 |
| && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat)) |
| && ! i2dest_in_i2src) |
| { |
| regno = REGNO (i2dest); |
| REG_N_SETS (regno)--; |
| } |
| } |
| |
| if (i1 && REG_P (i1dest)) |
| { |
| rtx link; |
| rtx i1_insn = 0, i1_val = 0, set; |
| |
| for (link = LOG_LINKS (i3); link; link = XEXP (link, 1)) |
| if ((set = single_set (XEXP (link, 0))) != 0 |
| && rtx_equal_p (i1dest, SET_DEST (set))) |
| i1_insn = XEXP (link, 0), i1_val = SET_SRC (set); |
| |
| record_value_for_reg (i1dest, i1_insn, i1_val); |
| |
| regno = REGNO (i1dest); |
| if (! added_sets_1 && ! i1dest_in_i1src) |
| REG_N_SETS (regno)--; |
| } |
| |
| /* Update reg_stat[].nonzero_bits et al for any changes that may have |
| been made to this insn. The order of |
| set_nonzero_bits_and_sign_copies() is important. Because newi2pat |
| can affect nonzero_bits of newpat */ |
| if (newi2pat) |
| note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL); |
| note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL); |
| |
| /* Set new_direct_jump_p if a new return or simple jump instruction |
| has been created. |
| |
| If I3 is now an unconditional jump, ensure that it has a |
| BARRIER following it since it may have initially been a |
| conditional jump. It may also be the last nonnote insn. */ |
| |
| if (returnjump_p (i3) || any_uncondjump_p (i3)) |
| { |
| *new_direct_jump_p = 1; |
| mark_jump_label (PATTERN (i3), i3, 0); |
| |
| if ((temp = next_nonnote_insn (i3)) == NULL_RTX |
| || !BARRIER_P (temp)) |
| emit_barrier_after (i3); |
| } |
| |
| if (undobuf.other_insn != NULL_RTX |
| && (returnjump_p (undobuf.other_insn) |
| || any_uncondjump_p (undobuf.other_insn))) |
| { |
| *new_direct_jump_p = 1; |
| |
| if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX |
| || !BARRIER_P (temp)) |
| emit_barrier_after (undobuf.other_insn); |
| } |
| |
| /* An NOOP jump does not need barrier, but it does need cleaning up |
| of CFG. */ |
| if (GET_CODE (newpat) == SET |
| && SET_SRC (newpat) == pc_rtx |
| && SET_DEST (newpat) == pc_rtx) |
| *new_direct_jump_p = 1; |
| } |
| |
| combine_successes++; |
| undo_commit (); |
| |
| if (added_links_insn |
| && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2)) |
| && INSN_CUID (added_links_insn) < INSN_CUID (i3)) |
| return added_links_insn; |
| else |
| return newi2pat ? i2 : i3; |
| } |
| |
| /* Undo all the modifications recorded in undobuf. */ |
| |
| static void |
| undo_all (void) |
| { |
| struct undo *undo, *next; |
| |
| for (undo = undobuf.undos; undo; undo = next) |
| { |
| next = undo->next; |
| if (undo->is_int) |
| *undo->where.i = undo->old_contents.i; |
| else |
| *undo->where.r = undo->old_contents.r; |
| |
| undo->next = undobuf.frees; |
| undobuf.frees = undo; |
| } |
| |
| undobuf.undos = 0; |
| } |
| |
| /* We've committed to accepting the changes we made. Move all |
| of the undos to the free list. */ |
| |
| static void |
| undo_commit (void) |
| { |
| struct undo *undo, *next; |
| |
| for (undo = undobuf.undos; undo; undo = next) |
| { |
| next = undo->next; |
| undo->next = undobuf.frees; |
| undobuf.frees = undo; |
| } |
| undobuf.undos = 0; |
| } |
| |
| |
| /* Find the innermost point within the rtx at LOC, possibly LOC itself, |
| where we have an arithmetic expression and return that point. LOC will |
| be inside INSN. |
| |
| try_combine will call this function to see if an insn can be split into |
| two insns. */ |
| |
| static rtx * |
| find_split_point (rtx *loc, rtx insn) |
| { |
| rtx x = *loc; |
| enum rtx_code code = GET_CODE (x); |
| rtx *split; |
| unsigned HOST_WIDE_INT len = 0; |
| HOST_WIDE_INT pos = 0; |
| int unsignedp = 0; |
| rtx inner = NULL_RTX; |
|