| /* Optimize by combining instructions for GNU compiler. |
| Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc. |
| |
| This file is part of GNU CC. |
| |
| GNU CC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU CC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU CC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| |
| /* This 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 |
| - reg_n_refs is not adjusted in the rare case when a register is |
| no longer required in a computation |
| - there are extremely rare cases (see distribute_regnotes) when a |
| REG_DEAD note is lost |
| - 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" |
| #ifdef __STDC__ |
| #include <stdarg.h> |
| #else |
| #include <varargs.h> |
| #endif |
| |
| /* Must precede rtl.h for FFS. */ |
| #include <stdio.h> |
| |
| #include "rtl.h" |
| #include "flags.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "expr.h" |
| #include "basic-block.h" |
| #include "insn-config.h" |
| #include "insn-flags.h" |
| #include "insn-codes.h" |
| #include "insn-attr.h" |
| #include "recog.h" |
| #include "real.h" |
| |
| /* It is not safe to use ordinary gen_lowpart in combine. |
| Use gen_lowpart_for_combine instead. See comments there. */ |
| #define gen_lowpart dont_use_gen_lowpart_you_dummy |
| |
| /* 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; |
| |
| /* Define a default value for REVERSIBLE_CC_MODE. |
| We can never assume that a condition code mode is safe to reverse unless |
| the md tells us so. */ |
| #ifndef REVERSIBLE_CC_MODE |
| #define REVERSIBLE_CC_MODE(MODE) 0 |
| #endif |
| |
| /* 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)]) |
| |
| /* Maximum register number, which is the size of the tables below. */ |
| |
| static int combine_max_regno; |
| |
| /* Record last point of death of (hard or pseudo) register n. */ |
| |
| static rtx *reg_last_death; |
| |
| /* Record last point of modification of (hard or pseudo) register n. */ |
| |
| static rtx *reg_last_set; |
| |
| /* 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 an insn that belongs before subst_insn, but is not currently |
| on the insn chain. */ |
| |
| static rtx subst_prev_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 number of the block in which we are performing combines. */ |
| static int this_basic_block; |
| |
| /* The next group of arrays allows the recording of the last value assigned |
| to (hard or pseudo) register n. We use this information to see if a |
| 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 arrays: |
| |
| reg_last_set_value the last value assigned |
| reg_last_set_label records the value of label_tick when the |
| register was assigned |
| reg_last_set_table_tick records the value of label_tick when a |
| value using the register is assigned |
| reg_last_set_invalid set to non-zero 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 reg_last_set_value being valid |
| and the register being validly contained in some other expression in the |
| table. |
| |
| Entry I in reg_last_set_value is valid if it is non-zero, and either |
| reg_n_sets[i] is 1 or reg_last_set_label[i] == 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_last_set_label[i] < reg_last_set_label[j] or |
| reg_last_set_invalid[j] is zero. |
| |
| 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)). |
| |
| reg_last_set_invalid[i] is set non-zero when register I is being assigned |
| to and reg_last_set_table_tick[i] == label_tick. */ |
| |
| /* Record last value assigned to (hard or pseudo) register n. */ |
| |
| static rtx *reg_last_set_value; |
| |
| /* Record the value of label_tick when the value for register n is placed in |
| reg_last_set_value[n]. */ |
| |
| static int *reg_last_set_label; |
| |
| /* Record the value of label_tick when an expression involving register n |
| is placed in reg_last_set_value. */ |
| |
| static int *reg_last_set_table_tick; |
| |
| /* Set non-zero if references to register n in expressions should not be |
| used. */ |
| |
| static char *reg_last_set_invalid; |
| |
| /* Incremented for each label. */ |
| |
| static int label_tick; |
| |
| /* 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 array 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. */ |
| |
| static unsigned HOST_WIDE_INT *reg_nonzero_bits; |
| |
| /* Mode used to compute significance in reg_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 if we know that a register has some leading bits that are always |
| equal to the sign bit. */ |
| |
| static char *reg_sign_bit_copies; |
| |
| /* Nonzero when reg_nonzero_bits and reg_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; |
| |
| /* These arrays are maintained in parallel with reg_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. */ |
| |
| static enum machine_mode *reg_last_set_mode; |
| static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits; |
| static char *reg_last_set_sign_bit_copies; |
| |
| /* 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. |
| |
| storage is nonzero if we must undo the allocation of new storage. |
| The value of storage is what to pass to obfree. |
| |
| other_insn is nonzero if we have modified some other insn in the process |
| of working on subst_insn. It must be verified too. |
| |
| previous_undos is the value of undobuf.undos when we started processing |
| this substitution. This will prevent gen_rtx_combine from re-used a piece |
| from the previous expression. Doing so can produce circular rtl |
| structures. */ |
| |
| struct undobuf |
| { |
| char *storage; |
| struct undo *undos; |
| struct undo *frees; |
| struct undo *previous_undos; |
| rtx other_insn; |
| }; |
| |
| static struct undobuf undobuf; |
| |
| /* 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. */ |
| |
| #define SUBST(INTO, NEWVAL) \ |
| do { rtx _new = (NEWVAL); \ |
| struct undo *_buf; \ |
| \ |
| if (undobuf.frees) \ |
| _buf = undobuf.frees, undobuf.frees = _buf->next; \ |
| else \ |
| _buf = (struct undo *) xmalloc (sizeof (struct undo)); \ |
| \ |
| _buf->is_int = 0; \ |
| _buf->where.r = &INTO; \ |
| _buf->old_contents.r = INTO; \ |
| INTO = _new; \ |
| if (_buf->old_contents.r == INTO) \ |
| _buf->next = undobuf.frees, undobuf.frees = _buf; \ |
| else \ |
| _buf->next = undobuf.undos, undobuf.undos = _buf; \ |
| } while (0) |
| |
| /* 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. */ |
| |
| #define SUBST_INT(INTO, NEWVAL) \ |
| do { struct undo *_buf; \ |
| \ |
| if (undobuf.frees) \ |
| _buf = undobuf.frees, undobuf.frees = _buf->next; \ |
| else \ |
| _buf = (struct undo *) xmalloc (sizeof (struct undo)); \ |
| \ |
| _buf->is_int = 1; \ |
| _buf->where.i = (int *) &INTO; \ |
| _buf->old_contents.i = INTO; \ |
| INTO = NEWVAL; \ |
| if (_buf->old_contents.i == INTO) \ |
| _buf->next = undobuf.frees, undobuf.frees = _buf; \ |
| else \ |
| _buf->next = undobuf.undos, undobuf.undos = _buf; \ |
| } while (0) |
| |
| /* Number of times the pseudo being substituted for |
| was found and replaced. */ |
| |
| static int n_occurrences; |
| |
| static void init_reg_last_arrays PROTO((void)); |
| static void setup_incoming_promotions PROTO((void)); |
| static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx)); |
| static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *)); |
| static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *)); |
| static rtx try_combine PROTO((rtx, rtx, rtx)); |
| static void undo_all PROTO((void)); |
| static rtx *find_split_point PROTO((rtx *, rtx)); |
| static rtx subst PROTO((rtx, rtx, rtx, int, int)); |
| static rtx simplify_rtx PROTO((rtx, enum machine_mode, int, int)); |
| static rtx simplify_if_then_else PROTO((rtx)); |
| static rtx simplify_set PROTO((rtx)); |
| static rtx simplify_logical PROTO((rtx, int)); |
| static rtx expand_compound_operation PROTO((rtx)); |
| static rtx expand_field_assignment PROTO((rtx)); |
| static rtx make_extraction PROTO((enum machine_mode, rtx, int, rtx, int, |
| int, int, int)); |
| static rtx extract_left_shift PROTO((rtx, int)); |
| static rtx make_compound_operation PROTO((rtx, enum rtx_code)); |
| static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *)); |
| static rtx force_to_mode PROTO((rtx, enum machine_mode, |
| unsigned HOST_WIDE_INT, rtx, int)); |
| static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *)); |
| static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx)); |
| static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx)); |
| static rtx make_field_assignment PROTO((rtx)); |
| static rtx apply_distributive_law PROTO((rtx)); |
| static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx, |
| unsigned HOST_WIDE_INT)); |
| static unsigned HOST_WIDE_INT nonzero_bits PROTO((rtx, enum machine_mode)); |
| static int num_sign_bit_copies PROTO((rtx, enum machine_mode)); |
| static int merge_outer_ops PROTO((enum rtx_code *, HOST_WIDE_INT *, |
| enum rtx_code, HOST_WIDE_INT, |
| enum machine_mode, int *)); |
| static rtx simplify_shift_const PROTO((rtx, enum rtx_code, enum machine_mode, |
| rtx, int)); |
| static int recog_for_combine PROTO((rtx *, rtx, rtx *, int *)); |
| static rtx gen_lowpart_for_combine PROTO((enum machine_mode, rtx)); |
| static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode, |
| ...)); |
| static rtx gen_binary PROTO((enum rtx_code, enum machine_mode, |
| rtx, rtx)); |
| static rtx gen_unary PROTO((enum rtx_code, enum machine_mode, |
| enum machine_mode, rtx)); |
| static enum rtx_code simplify_comparison PROTO((enum rtx_code, rtx *, rtx *)); |
| static int reversible_comparison_p PROTO((rtx)); |
| static void update_table_tick PROTO((rtx)); |
| static void record_value_for_reg PROTO((rtx, rtx, rtx)); |
| static void record_dead_and_set_regs_1 PROTO((rtx, rtx)); |
| static void record_dead_and_set_regs PROTO((rtx)); |
| static int get_last_value_validate PROTO((rtx *, rtx, int, int)); |
| static rtx get_last_value PROTO((rtx)); |
| static int use_crosses_set_p PROTO((rtx, int)); |
| static void reg_dead_at_p_1 PROTO((rtx, rtx)); |
| static int reg_dead_at_p PROTO((rtx, rtx)); |
| static void move_deaths PROTO((rtx, rtx, int, rtx, rtx *)); |
| static int reg_bitfield_target_p PROTO((rtx, rtx)); |
| static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx)); |
| static void distribute_links PROTO((rtx)); |
| static void mark_used_regs_combine PROTO((rtx)); |
| static int insn_cuid PROTO((rtx)); |
| |
| /* Main entry point for combiner. F is the first insn of the function. |
| NREGS is the first unused pseudo-reg number. */ |
| |
| void |
| combine_instructions (f, nregs) |
| rtx f; |
| int nregs; |
| { |
| register rtx insn, next, prev; |
| register int i; |
| register rtx links, nextlinks; |
| |
| combine_attempts = 0; |
| combine_merges = 0; |
| combine_extras = 0; |
| combine_successes = 0; |
| undobuf.undos = undobuf.previous_undos = 0; |
| |
| combine_max_regno = nregs; |
| |
| reg_nonzero_bits |
| = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT)); |
| reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char)); |
| |
| bzero ((char *) reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT)); |
| bzero (reg_sign_bit_copies, nregs * sizeof (char)); |
| |
| reg_last_death = (rtx *) alloca (nregs * sizeof (rtx)); |
| reg_last_set = (rtx *) alloca (nregs * sizeof (rtx)); |
| reg_last_set_value = (rtx *) alloca (nregs * sizeof (rtx)); |
| reg_last_set_table_tick = (int *) alloca (nregs * sizeof (int)); |
| reg_last_set_label = (int *) alloca (nregs * sizeof (int)); |
| reg_last_set_invalid = (char *) alloca (nregs * sizeof (char)); |
| reg_last_set_mode |
| = (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode)); |
| reg_last_set_nonzero_bits |
| = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT)); |
| reg_last_set_sign_bit_copies |
| = (char *) alloca (nregs * sizeof (char)); |
| |
| init_reg_last_arrays (); |
| |
| 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 = (int *) alloca ((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_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; |
| |
| /* We need to initialize it here, because record_dead_and_set_regs may call |
| get_last_value. */ |
| subst_prev_insn = NULL_RTX; |
| |
| setup_incoming_promotions (); |
| |
| for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) |
| { |
| uid_cuid[INSN_UID (insn)] = ++i; |
| subst_low_cuid = i; |
| subst_insn = insn; |
| |
| if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') |
| { |
| note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies); |
| 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); |
| #endif |
| } |
| |
| if (GET_CODE (insn) == CODE_LABEL) |
| label_tick++; |
| } |
| |
| nonzero_sign_valid = 1; |
| |
| /* Now scan all the insns in forward order. */ |
| |
| this_basic_block = -1; |
| label_tick = 1; |
| last_call_cuid = 0; |
| mem_last_set = 0; |
| init_reg_last_arrays (); |
| setup_incoming_promotions (); |
| |
| for (insn = f; insn; insn = next ? next : NEXT_INSN (insn)) |
| { |
| next = 0; |
| |
| /* If INSN starts a new basic block, update our basic block number. */ |
| if (this_basic_block + 1 < n_basic_blocks |
| && basic_block_head[this_basic_block + 1] == insn) |
| this_basic_block++; |
| |
| if (GET_CODE (insn) == CODE_LABEL) |
| label_tick++; |
| |
| else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') |
| { |
| /* 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)) != 0) |
| goto retry; |
| |
| /* Try each sequence of three linked insns ending with this one. */ |
| |
| for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) |
| for (nextlinks = LOG_LINKS (XEXP (links, 0)); nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, XEXP (links, 0), |
| XEXP (nextlinks, 0))) != 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 (GET_CODE (insn) == JUMP_INSN |
| && (prev = prev_nonnote_insn (insn)) != 0 |
| && GET_CODE (prev) == INSN |
| && sets_cc0_p (PATTERN (prev))) |
| { |
| if ((next = try_combine (insn, prev, NULL_RTX)) != 0) |
| goto retry; |
| |
| for (nextlinks = LOG_LINKS (prev); nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, prev, |
| XEXP (nextlinks, 0))) != 0) |
| goto retry; |
| } |
| |
| /* Do the same for an insn that explicitly references CC0. */ |
| if (GET_CODE (insn) == INSN |
| && (prev = prev_nonnote_insn (insn)) != 0 |
| && GET_CODE (prev) == INSN |
| && 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)) != 0) |
| goto retry; |
| |
| for (nextlinks = LOG_LINKS (prev); nextlinks; |
| nextlinks = XEXP (nextlinks, 1)) |
| if ((next = try_combine (insn, prev, |
| XEXP (nextlinks, 0))) != 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 (GET_CODE (XEXP (links, 0)) == INSN |
| && 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 |
| && GET_CODE (prev) == INSN |
| && sets_cc0_p (PATTERN (prev)) |
| && (next = try_combine (insn, XEXP (links, 0), prev)) != 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))) != 0) |
| goto retry; |
| |
| if (GET_CODE (insn) != NOTE) |
| record_dead_and_set_regs (insn); |
| |
| retry: |
| ; |
| } |
| } |
| |
| total_attempts += combine_attempts; |
| total_merges += combine_merges; |
| total_extras += combine_extras; |
| total_successes += combine_successes; |
| |
| nonzero_sign_valid = 0; |
| } |
| |
| /* Wipe the reg_last_xxx arrays in preparation for another pass. */ |
| |
| static void |
| init_reg_last_arrays () |
| { |
| int nregs = combine_max_regno; |
| |
| bzero ((char *) reg_last_death, nregs * sizeof (rtx)); |
| bzero ((char *) reg_last_set, nregs * sizeof (rtx)); |
| bzero ((char *) reg_last_set_value, nregs * sizeof (rtx)); |
| bzero ((char *) reg_last_set_table_tick, nregs * sizeof (int)); |
| bzero ((char *) reg_last_set_label, nregs * sizeof (int)); |
| bzero (reg_last_set_invalid, nregs * sizeof (char)); |
| bzero ((char *) reg_last_set_mode, nregs * sizeof (enum machine_mode)); |
| bzero ((char *) reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT)); |
| bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char)); |
| } |
| |
| /* Set up any promoted values for incoming argument registers. */ |
| |
| static void |
| setup_incoming_promotions () |
| { |
| #ifdef PROMOTE_FUNCTION_ARGS |
| int regno; |
| rtx reg; |
| enum machine_mode mode; |
| int unsignedp; |
| rtx first = get_insns (); |
| |
| for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) |
| if (FUNCTION_ARG_REGNO_P (regno) |
| && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0) |
| record_value_for_reg (reg, first, |
| gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, |
| GET_MODE (reg), |
| gen_rtx (CLOBBER, mode, const0_rtx))); |
| #endif |
| } |
| |
| /* 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 (x, set) |
| rtx x; |
| rtx set; |
| { |
| int num; |
| |
| if (GET_CODE (x) == REG |
| && 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 (basic_block_live_at_start[0], REGNO (x)) |
| && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT) |
| { |
| if (set == 0 || GET_CODE (set) == CLOBBER) |
| { |
| reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); |
| reg_sign_bit_copies[REGNO (x)] = 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_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 |
| |
| reg_nonzero_bits[REGNO (x)] |
| |= nonzero_bits (src, nonzero_bits_mode); |
| num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); |
| if (reg_sign_bit_copies[REGNO (x)] == 0 |
| || reg_sign_bit_copies[REGNO (x)] > num) |
| reg_sign_bit_copies[REGNO (x)] = num; |
| } |
| else |
| { |
| reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); |
| reg_sign_bit_copies[REGNO (x)] = 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 (insn, i3, pred, succ, pdest, psrc) |
| rtx insn; |
| rtx i3; |
| rtx pred, succ; |
| rtx *pdest, *psrc; |
| { |
| int i; |
| rtx set = 0, src, dest; |
| rtx p, link; |
| 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); |
| |
| switch (GET_CODE (elt)) |
| { |
| /* 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)) |
| && ! 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 |
| /* If we couldn't eliminate a field assignment, we can't combine. */ |
| || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART |
| /* 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 a function call. */ |
| || GET_CODE (src) == CALL |
| /* Don't eliminate a function call argument. */ |
| || (GET_CODE (i3) == CALL_INSN |
| && (find_reg_fusage (i3, USE, dest) |
| || (GET_CODE (dest) == REG |
| && 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 combine the end of a libcall into anything. */ |
| || find_reg_note (insn, REG_RETVAL, NULL_RTX) |
| /* 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; reg_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 |
| && (((GET_CODE (src) != MEM |
| || ! 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 (GET_CODE (dest) == REG) |
| { |
| /* 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. |
| |
| This is the same test done in can_combine except that we don't test |
| if SRC is a CALL operation to permit a hard register with |
| SMALL_REGISTER_CLASSES, and that we have to take all_adjacent |
| into account. */ |
| |
| if (GET_CODE (src) == REG |
| && ((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)) |
| #ifdef SMALL_REGISTER_CLASSES |
| || (SMALL_REGISTER_CLASSES |
| && ((! all_adjacent && ! REG_USERVAR_P (src)) |
| || (FUNCTION_VALUE_REGNO_P (REGNO (src)) |
| && ! REG_USERVAR_P (src)))) |
| #endif |
| )))) |
| return 0; |
| } |
| else if (GET_CODE (dest) != CC0) |
| return 0; |
| |
| /* Don't substitute for a register intended as a clobberable operand. |
| Similarly, don't substitute an expression containing a register that |
| will be clobbered in I3. */ |
| 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 |
| && (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), |
| src) |
| || rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest))) |
| return 0; |
| |
| /* If INSN contains anything volatile, or is an `asm' (whether volatile |
| or not), reject, unless nothing volatile comes between it and I3, |
| with the exception of SUCC. */ |
| |
| if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src)) |
| for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p)) |
| if (GET_RTX_CLASS (GET_CODE (p)) == 'i' |
| && p != succ && volatile_refs_p (PATTERN (p))) |
| 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 (GET_RTX_CLASS (GET_CODE (p)) == 'i' |
| && p != succ && volatile_insn_p (PATTERN (p))) |
| return 0; |
| |
| /* If INSN or I2 contains an autoincrement or autodecrement, |
| make sure that register is not used between there and I3, |
| and not already used in I3 either. |
| 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 |
| && (GET_CODE (i3) == JUMP_INSN |
| || reg_used_between_p (XEXP (link, 0), insn, i3) |
| || 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 && GET_CODE (p) == INSN && 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 non-zero, it means that finding I1 in the source |
| of a SET must prevent combination from occurring. |
| |
| On machines where SMALL_REGISTER_CLASSES is defined, we don't combine |
| if the destination of a SET is a hard register that isn't a user |
| variable. |
| |
| Before doing the above check, we first try to expand a field assignment |
| into a set of logical operations. |
| |
| If PI3_DEST_KILLED is non-zero, 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 (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed) |
| 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 = expand_field_assignment (x); |
| rtx dest = SET_DEST (set); |
| rtx src = SET_SRC (set); |
| rtx inner_dest = dest, inner_src = src; |
| |
| SUBST (*loc, set); |
| |
| 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); |
| |
| /* We probably don't need this any more now that LIMIT_RELOAD_CLASS |
| was added. */ |
| #if 0 |
| while (GET_CODE (inner_src) == STRICT_LOW_PART |
| || GET_CODE (inner_src) == SUBREG |
| || GET_CODE (inner_src) == ZERO_EXTRACT) |
| inner_src = XEXP (inner_src, 0); |
| |
| /* If it is better that two different modes keep two different pseudos, |
| avoid combining them. This avoids producing the following pattern |
| on a 386: |
| (set (subreg:SI (reg/v:QI 21) 0) |
| (lshiftrt:SI (reg/v:SI 20) |
| (const_int 24))) |
| If that were made, reload could not handle the pair of |
| reg 20/21, since it would try to get any GENERAL_REGS |
| but some of them don't handle QImode. */ |
| |
| if (rtx_equal_p (inner_src, i2dest) |
| && GET_CODE (inner_dest) == REG |
| && ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (inner_dest))) |
| return 0; |
| #endif |
| |
| /* Check for the case where I3 modifies its output, as |
| discussed above. */ |
| if ((inner_dest != 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 that we |
| allow a hard register with SMALL_REGISTER_CLASSES if SRC is a |
| CALL operation. |
| Moreover, we can't test all_adjacent; we don't have to, since |
| this instruction will stay in place, thus we are not considering |
| to increase the lifetime of INNER_DEST. */ |
| || (GET_CODE (inner_dest) == REG |
| && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER |
| && (! HARD_REGNO_MODE_OK (REGNO (inner_dest), |
| GET_MODE (inner_dest)) |
| #ifdef SMALL_REGISTER_CLASSES |
| || (SMALL_REGISTER_CLASSES |
| && GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest) |
| && FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))) |
| #endif |
| )) |
| || (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 && GET_CODE (dest) == REG |
| && 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; |
| } |
| |
| /* 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. |
| |
| It 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. */ |
| |
| static rtx |
| try_combine (i3, i2, i1) |
| register rtx i3, i2, i1; |
| { |
| /* New patterns for I3 and I3, respectively. */ |
| rtx newpat, newi2pat = 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 is 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, other_code_number; |
| /* 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; |
| /* Number of clobbers of SCRATCH we had to add. */ |
| int i3_scratches = 0, i2_scratches = 0, other_scratches = 0; |
| |
| int maxreg; |
| rtx temp; |
| register rtx link; |
| int i; |
| |
| /* If any of I1, I2, and I3 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. 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 (GET_RTX_CLASS (GET_CODE (i3)) != 'i' |
| || GET_RTX_CLASS (GET_CODE (i2)) != 'i' |
| || (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i') |
| || find_reg_note (i3, REG_LIBCALL, NULL_RTX)) |
| return 0; |
| |
| combine_attempts++; |
| |
| undobuf.undos = undobuf.previous_undos = 0; |
| undobuf.other_insn = 0; |
| |
| /* Save the current high-water-mark so we can free storage if we didn't |
| accept this combination. */ |
| undobuf.storage = (char *) oballoc (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 has multiple sets, |
| 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. |
| |
| 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 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET |
| && GET_CODE (SET_SRC (PATTERN (i3))) == REG |
| && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER |
| #ifdef SMALL_REGISTER_CLASSES |
| && (! SMALL_REGISTER_CLASSES |
| || GET_CODE (SET_DEST (PATTERN (i3))) != REG |
| || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER |
| || REG_USERVAR_P (SET_DEST (PATTERN (i3)))) |
| #endif |
| && 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 (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; |
| } |
| } |
| |
| #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 |
| && GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 1))) == REG |
| && 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. */ |
| |
| subst_prev_insn = i1 |
| = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2, |
| XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0); |
| |
| 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 |
| && GET_CODE (SET_SRC (PATTERN (i3))) == REG |
| && GET_CODE (SET_DEST (PATTERN (i3))) == MEM |
| && (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. |
| The cases that we are interested in here do not involve the few |
| cases were is_replaced is checked. */ |
| 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); |
| } |
| |
| undobuf.previous_undos = undobuf.undos; |
| } |
| |
| #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)) |
| { |
| rtx *cc_use; |
| enum machine_mode compare_mode; |
| |
| newpat = PATTERN (i3); |
| SUBST (XEXP (SET_SRC (newpat), 0), i2src); |
| |
| i2_is_used = 1; |
| |
| #ifdef EXTRA_CC_MODES |
| /* 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)))) |
| { |
| 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_combine (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); |
| undobuf.previous_undos = undobuf.undos; |
| |
| /* 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, NULL_PTR)) |
| { |
| undo_all (); |
| return 0; |
| } |
| |
| n_occurrences = 0; |
| subst_low_cuid = INSN_CUID (i1); |
| newpat = subst (newpat, i1dest, i1src, 0, 0); |
| undobuf.previous_undos = undobuf.undos; |
| } |
| |
| /* 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)); |
| bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem, |
| 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, &i3_scratches); |
| |
| /* 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. 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. 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 && GET_CODE (newpat) == PARALLEL |
| && XVECLEN (newpat, 0) == 2 |
| && GET_CODE (XVECEXP (newpat, 0, 0)) == SET |
| && GET_CODE (XVECEXP (newpat, 0, 1)) == SET |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == REG |
| && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 1))) |
| && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 1))) |
| && asm_noperands (newpat) < 0) |
| { |
| newpat = XVECEXP (newpat, 0, 0); |
| insn_code_number |
| = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches); |
| } |
| |
| else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL |
| && XVECLEN (newpat, 0) == 2 |
| && GET_CODE (XVECEXP (newpat, 0, 0)) == SET |
| && GET_CODE (XVECEXP (newpat, 0, 1)) == SET |
| && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) == REG |
| && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 0))) |
| && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 0))) |
| && asm_noperands (newpat) < 0) |
| { |
| newpat = XVECEXP (newpat, 0, 1); |
| insn_code_number |
| = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches); |
| } |
| |
| /* 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 |
| && GET_CODE (i2dest) == REG |
| && (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 (m_split && GET_CODE (m_split) == SEQUENCE |
| && XVECLEN (m_split, 0) == 2 |
| && (next_real_insn (i2) == i3 |
| || ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)), |
| INSN_CUID (i2)))) |
| { |
| rtx i2set, i3set; |
| rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1)); |
| newi2pat = PATTERN (XVECEXP (m_split, 0, 0)); |
| |
| i3set = single_set (XVECEXP (m_split, 0, 1)); |
| i2set = single_set (XVECEXP (m_split, 0, 0)); |
| |
| /* 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, |
| &i2_scratches); |
| |
| /* 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, |
| &i3_scratches); |
| 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 (GET_CODE (new_i3_dest) == REG |
| && GET_CODE (new_i2_dest) == REG |
| && 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 |
| && GET_CODE (i2dest) == REG |
| #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 |
| && (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0) |
| { |
| SUBST (*split, gen_rtx_combine (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 && GET_CODE (SUBREG_REG (*split)) == MEM) |
| SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode, |
| XEXP (*split, 0))); |
| #endif |
| |
| newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split); |
| SUBST (*split, newdest); |
| i2_code_number |
| = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches); |
| |
| /* 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, &i3_scratches); |
| } |
| } |
| |
| /* 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 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_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)), |
| (GET_CODE (temp) == REG |
| && reg_nonzero_bits[REGNO (temp)] != 0 |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT |
| && (reg_nonzero_bits[REGNO (temp)] |
| != GET_MODE_MASK (word_mode)))) |
| && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG |
| && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))), |
| (GET_CODE (temp) == REG |
| && reg_nonzero_bits[REGNO (temp)] != 0 |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD |
| && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT |
| && (reg_nonzero_bits[REGNO (temp)] |
| != 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_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest)); |
| i2_code_number |
| = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches); |
| |
| if (i2_code_number >= 0) |
| insn_code_number |
| = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches); |
| |
| if (insn_code_number >= 0) |
| { |
| rtx insn; |
| rtx link; |
| |
| /* If we will be able to accept this, we have made a change to the |
| destination of I3. This can invalidate a LOG_LINKS pointing |
| to I3. No other part of combine.c makes such a transformation. |
| |
| The new I3 will have a destination that was previously the |
| destination of I1 or I2 and which was used in i2 or I3. Call |
| distribute_links to make a LOG_LINK from the next use of |
| that destination. */ |
| |
| PATTERN (i3) = newpat; |
| distribute_links (gen_rtx (INSN_LIST, VOIDmode, i3, NULL_RTX)); |
| |
| /* I3 now uses what used to be its destination and which is |
| now I2's destination. That means 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. */ |
| |
| for (insn = NEXT_INSN (i3); |
| insn && (this_basic_block == n_basic_blocks - 1 |
| || insn != basic_block_head[this_basic_block + 1]); |
| insn = NEXT_INSN (insn)) |
| { |
| if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' |
| && 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; |
| } |
| } |
| } |
| } |
| |
| /* 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))) |
| { |
| newi2pat = XVECEXP (newpat, 0, 1); |
| newpat = XVECEXP (newpat, 0, 0); |
| |
| i2_code_number |
| = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches); |
| |
| if (i2_code_number >= 0) |
| insn_code_number |
| = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches); |
| } |
| |
| /* 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, &other_scratches); |
| |
| 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 (GET_CODE (XEXP (note, 0)) == REG) |
| REG_N_DEATHS (REGNO (XEXP (note, 0)))--; |
| |
| remove_note (undobuf.other_insn, note); |
| } |
| } |
| |
| for (note = new_other_notes; note; note = XEXP (note, 1)) |
| if (GET_CODE (XEXP (note, 0)) == REG) |
| REG_N_DEATHS (REGNO (XEXP (note, 0)))++; |
| |
| distribute_notes (new_other_notes, undobuf.other_insn, |
| undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX); |
| } |
| |
| /* We now know that we can do this combination. Merge the insns and |
| update the status of registers and LOG_LINKS. */ |
| |
| { |
| rtx i3notes, i2notes, i1notes = 0; |
| rtx i3links, i2links, i1links = 0; |
| rtx midnotes = 0; |
| register int regno; |
| /* Compute which registers we expect to eliminate. */ |
| rtx elim_i2 = (newi2pat || i2dest_in_i2src || i2dest_in_i1src |
| ? 0 : i2dest); |
| rtx elim_i1 = i1 == 0 || i1dest_in_i1src ? 0 : i1dest; |
| |
| /* 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 (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 (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG |
| && 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 == n_basic_blocks - 1 |
| || basic_block_head[this_basic_block] != temp); |
| temp = NEXT_INSN (temp)) |
| if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i') |
| 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 |
| { |
| PUT_CODE (i2, NOTE); |
| NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED; |
| NOTE_SOURCE_FILE (i2) = 0; |
| } |
| |
| if (i1) |
| { |
| LOG_LINKS (i1) = 0; |
| REG_NOTES (i1) = 0; |
| PUT_CODE (i1, NOTE); |
| NOTE_LINE_NUMBER (i1) = NOTE_INSN_DELETED; |
| NOTE_SOURCE_FILE (i1) = 0; |
| } |
| |
| /* 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, |
| elim_i2, elim_i1); |
| if (i2notes) |
| distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX, |
| elim_i2, elim_i1); |
| if (i1notes) |
| distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX, |
| elim_i2, elim_i1); |
| if (midnotes) |
| distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, |
| elim_i2, elim_i1); |
| |
| /* 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 (GET_CODE (XEXP (temp, 0)) == REG) |
| REG_N_DEATHS (REGNO (XEXP (temp, 0)))++; |
| |
| distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX); |
| } |
| |
| if (new_i3_notes) |
| { |
| for (temp = new_i3_notes; temp; temp = XEXP (temp, 1)) |
| if (GET_CODE (XEXP (temp, 0)) == REG) |
| REG_N_DEATHS (REGNO (XEXP (temp, 0)))++; |
| |
| distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, 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. 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 (GET_CODE (i3dest_killed) == REG) |
| REG_N_DEATHS (REGNO (i3dest_killed))++; |
| |
| distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i3dest_killed, |
| NULL_RTX), |
| NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, |
| NULL_RTX, NULL_RTX); |
| } |
| |
| /* For I2 and I1, we have to be careful. If NEWI2PAT exists and sets |
| I2DEST or I1DEST, the death must be somewhere before I2, not I3. If |
| we passed I3 in that case, it might delete I2. */ |
| |
| if (i2dest_in_i2src) |
| { |
| if (GET_CODE (i2dest) == REG) |
| 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, NULL_RTX, NULL_RTX); |
| else |
| distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX), |
| NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, |
| NULL_RTX, NULL_RTX); |
| } |
| |
| if (i1dest_in_i1src) |
| { |
| if (GET_CODE (i1dest) == REG) |
| 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, NULL_RTX, NULL_RTX); |
| else |
| distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX), |
| NULL_RTX, i3, newi2pat ? i2 : NULL_RTX, |
| NULL_RTX, NULL_RTX); |
| } |
| |
| distribute_links (i3links); |
| distribute_links (i2links); |
| distribute_links (i1links); |
| |
| if (GET_CODE (i2dest) == REG) |
| { |
| 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 (REG_N_SETS (regno) == 0 |
| && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno)) |
| REG_N_REFS (regno) = 0; |
| } |
| } |
| |
| if (i1 && GET_CODE (i1dest) == REG) |
| { |
| 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)--; |
| if (REG_N_SETS (regno) == 0 |
| && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno)) |
| REG_N_REFS (regno) = 0; |
| } |
| } |
| |
| /* Update reg_nonzero_bits et al for any changes that may have been made |
| to this insn. */ |
| |
| note_stores (newpat, set_nonzero_bits_and_sign_copies); |
| if (newi2pat) |
| note_stores (newi2pat, set_nonzero_bits_and_sign_copies); |
| |
| /* If we added any (clobber (scratch)), add them to the max for a |
| block. This is a very pessimistic calculation, since we might |
| have had them already and this might not be the worst block, but |
| it's not worth doing any better. */ |
| max_scratch += i3_scratches + i2_scratches + other_scratches; |
| |
| /* 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 ((GET_CODE (newpat) == RETURN || simplejump_p (i3)) |
| && ((temp = next_nonnote_insn (i3)) == NULL_RTX |
| || GET_CODE (temp) != BARRIER)) |
| emit_barrier_after (i3); |
| } |
| |
| combine_successes++; |
| |
| /* Clear this here, so that subsequent get_last_value calls are not |
| affected. */ |
| subst_prev_insn = NULL_RTX; |
| |
| 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 () |
| { |
| 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; |
| } |
| |
| obfree (undobuf.storage); |
| undobuf.undos = undobuf.previous_undos = 0; |
| |
| /* Clear this here, so that subsequent get_last_value calls are not |
| affected. */ |
| subst_prev_insn = NULL_RTX; |
| } |
| |
| /* 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 (loc, insn) |
| rtx *loc; |
| rtx insn; |
| { |
| rtx x = *loc; |
| enum rtx_code code = GET_CODE (x); |
| rtx *split; |
| int len = 0, pos, unsignedp; |
| rtx inner; |
| |
| /* First special-case some codes. */ |
| switch (code) |
| { |
| case SUBREG: |
| #ifdef INSN_SCHEDULING |
| /* If we are making a paradoxical SUBREG invalid, it becomes a split |
| point. */ |
| if (GET_CODE (SUBREG_REG (x)) == MEM) |
| return loc; |
| #endif |
| return find_split_point (&SUBREG_REG (x), insn); |
| |
| case MEM: |
| #ifdef HAVE_lo_sum |
| /* If we have (mem (const ..)) or (mem (symbol_ref ...)), split it |
| using LO_SUM and HIGH. */ |
| if (GET_CODE (XEXP (x, 0)) == CONST |
| || GET_CODE (XEXP (x, 0)) == SYMBOL_REF) |
| { |
| SUBST (XEXP (x, 0), |
| gen_rtx_combine (LO_SUM, Pmode, |
| gen_rtx_combine (HIGH, Pmode, XEXP (x, 0)), |
| XEXP (x, 0))); |
| return &XEXP (XEXP (x, 0), 0); |
| } |
| #endif |
| |
| /* If we have a PLUS whose second operand is a constant and the |
| address is not valid, perhaps will can split it up using |
| the machine-specific way to split large constants. We use |
| the first pseudo-reg (one of the virtual regs) as a placeholder; |
| it will not remain in the result. */ |
| if (GET_CODE (XEXP (x, 0)) == PLUS |
| && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT |
| && ! memory_address_p (GET_MODE (x), XEXP (x, 0))) |
| { |
| rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER]; |
| rtx seq = split_insns (gen_rtx (SET, VOIDmode, reg, XEXP (x, 0)), |
| subst_insn); |
| |
| /* This should have produced two insns, each of which sets our |
| placeholder. If the source of the second is a valid address, |
| we can make put both sources together and make a split point |
| in the middle. */ |
| |
| if (seq && XVECLEN (seq, 0) == 2 |
| && GET_CODE (XVECEXP (seq, 0, 0)) == INSN |
| && GET_CODE (PATTERN (XVECEXP (seq, 0, 0))) == SET |
| && SET_DEST (PATTERN (XVECEXP (seq, 0, 0))) == reg |
| && ! reg_mentioned_p (reg, |
| SET_SRC (PATTERN (XVECEXP (seq, 0, 0)))) |
| && GET_CODE (XVECEXP (seq, 0, 1)) == INSN |
| && GET_CODE (PATTERN (XVECEXP (seq, 0, 1))) == SET |
| && SET_DEST (PATTERN (XVECEXP (seq, 0, 1))) == reg |
| && memory_address_p (GET_MODE (x), |
| SET_SRC (PATTERN (XVECEXP (seq, 0, 1))))) |
| { |
| rtx src1 = SET_SRC (PATTERN (XVECEXP (seq, 0, 0))); |
| rtx src2 = SET_SRC (PATTERN (XVECEXP (seq, 0, 1))); |
| |
| /* Replace the placeholder in SRC2 with SRC1. If we can |
| find where in SRC2 it was placed, that can become our |
| split point and we can replace this address with SRC2. |
| Just try two obvious places. */ |
| |
| src2 = replace_rtx (src2, reg, src1); |
| split = 0; |
| if (XEXP (src2, 0) == src1) |
| split = &XEXP (src2, 0); |
| else if (GET_RTX_FORMAT (GET_CODE (XEXP (src2, 0)))[0] == 'e' |
| && XEXP (XEXP (src2, 0), 0) == src1) |
| split = &XEXP (XEXP (src2, 0), 0); |
| |
| if (split) |
| { |
| SUBST (XEXP (x, 0), src2); |
| return split; |
| } |
| } |
| |
| /* If that didn't work, perhaps the first operand is complex and |
| needs to be computed separately, so make a split point there. |
| This will occur on machines that just support REG + CONST |
| and have a constant moved through some previous computation. */ |
| |
| else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o' |
| && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG |
| && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0)))) |
| == 'o'))) |
| return &XEXP (XEXP (x, 0), 0); |
| } |
| break; |
| |
| case SET: |
| #ifdef HAVE_cc0 |
| /* If SET_DEST is CC0 and SET_SRC is not an operand, a COMPARE, or a |
| ZERO_EXTRACT, the most likely reason why this doesn't match is that |
| we need to put the operand into a register. So split at that |
| point. */ |
| |
| if (SET_DEST (x) == cc0_rtx |
| && GET_CODE (SET_SRC (x)) != COMPARE |
| && GET_CODE (SET_SRC (x)) != ZERO_EXTRACT |
| && GET_RTX_CLASS (GET_CODE (SET_SRC (x))) != 'o' |
| && ! (GET_CODE (SET_SRC (x)) == SUBREG |
| && GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) == 'o')) |
| return &SET_SRC (x); |
| #endif |
| |
| /* See if we can split SET_SRC as it stands. */ |
| split = find_split_point (&SET_SRC (x), insn); |
| if (split && split != &SET_SRC (x)) |
| return split; |
| |
| /* See if we can split SET_DEST as it stands. */ |
| split = find_split_point (&SET_DEST (x), insn); |
| if (split && split != &SET_DEST (x)) |
| return split; |
| |
| /* See if this is a bitfield assignment with everything constant. If |
| so, this is an IOR of an AND, so split it into that. */ |
| if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT |
| && (GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0))) |
| <= HOST_BITS_PER_WIDE_INT) |
| && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT |
| && GET_CODE (XEXP (SET_DEST (x), 2)) == CONST_INT |
| && GET_CODE (SET_SRC (x)) == CONST_INT |
| && ((INTVAL (XEXP (SET_DEST (x), 1)) |
| + INTVAL (XEXP (SET_DEST (x), 2))) |
| <= GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)))) |
| && ! side_effects_p (XEXP (SET_DEST (x), 0))) |
| { |
| int pos = INTVAL (XEXP (SET_DEST (x), 2)); |
| int len = INTVAL (XEXP (SET_DEST (x), 1)); |
| int src = INTVAL (SET_SRC (x)); |
| rtx dest = XEXP (SET_DEST (x), 0); |
| enum machine_mode mode = GET_MODE (dest); |
| unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1; |
| |
| if (BITS_BIG_ENDIAN) |
| pos = GET_MODE_BITSIZE (mode) - len - pos; |
| |
| if (src == mask) |
| SUBST (SET_SRC (x), |
| gen_binary (IOR, mode, dest, GEN_INT (src << pos))); |
| else |
| SUBST (SET_SRC (x), |
| gen_binary (IOR, mode, |
| gen_binary (AND, mode, dest, |
| GEN_INT (~ (mask << pos) |
| & GET_MODE_MASK (mode))), |
| GEN_INT (src << pos))); |
| |
| SUBST (SET_DEST (x), dest); |
| |
| split = find_split_point (&SET_SRC (x), insn); |
| if (split && split != &SET_SRC (x)) |
| return split; |
| } |
| |
| /* Otherwise, see if this is an operation that we can split into two. |
| If so, try to split that. */ |
| code = GET_CODE (SET_SRC (x)); |
| |
| switch (code) |
| { |
| case AND: |
| /* If we are AND'ing with a large constant that is only a single |
| bit and the result is only being used in a context where we |
| need to know if it is zero or non-zero, replace it with a bit |
| extraction. This will avoid the large constant, which might |
| have taken more than one insn to make. If the constant were |
| not a valid argument to the AND but took only one insn to make, |
| this is no worse, but if it took more than one insn, it will |
| be better. */ |
| |
| if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT |
| && GET_CODE (XEXP (SET_SRC (x), 0)) == REG |
| && (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7 |
| && GET_CODE (SET_DEST (x)) == REG |
| && (split = find_single_use (SET_DEST (x), insn, NULL_PTR)) != 0 |
| && (GET_CODE (*split) == EQ || GET_CODE (*split) == NE) |
| && XEXP (*split, 0) == SET_DEST (x) |
| && XEXP (*split, 1) == const0_rtx) |
| { |
| rtx extraction = make_extraction (GET_MODE (SET_DEST (x)), |
| XEXP (SET_SRC (x), 0), |
| pos, NULL_RTX, 1, 1, 0, 0); |
| if (extraction != 0) |
| { |
| SUBST (SET_SRC (x), extraction); |
| return find_split_point (loc, insn); |
| } |
| } |
| break; |
| |
| case NE: |
| /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X |
| is known to be on, this can be converted into a NEG of a shift. */ |
| if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx |
| && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0)) |
| && 1 <= (pos = exact_log2 |
| (nonzero_bits (XEXP (SET_SRC (x), 0), |
| GET_MODE (XEXP (SET_SRC (x), 0)))))) |
| { |
| enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0)); |
| |
| SUBST (SET_SRC (x), |
| gen_rtx_combine (NEG, mode, |
| gen_rtx_combine (LSHIFTRT, mode, |
| XEXP (SET_SRC (x), 0), |
| GEN_INT (pos)))); |
| |
| split = find_split_point (&SET_SRC (x), insn); |
| if (split && split != &SET_SRC (x)) |
| return split; |
| } |
| break; |
| |
| case SIGN_EXTEND: |
| inner = XEXP (SET_SRC (x), 0); |
| |
| /* We can't optimize if either mode is a partial integer |
| mode as we don't know how many bits are significant |
| in those modes. */ |
| if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT |
| || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT) |
| break; |
| |
| pos = 0; |
| len = GET_MODE_BITSIZE (GET_MODE (inner)); |
| unsignedp = 0; |
| break; |
| |
| case SIGN_EXTRACT: |
| case ZERO_EXTRACT: |
| if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT |
| && GET_CODE (XEXP (SET_SRC (x), 2)) == CONST_INT) |
| { |
| inner = XEXP (SET_SRC (x), 0); |
| len = INTVAL (XEXP (SET_SRC (x), 1)); |
| pos = INTVAL (XEXP (SET_SRC (x), 2)); |
| |
| if (BITS_BIG_ENDIAN) |
| pos = GET_MODE_BITSIZE (GET_MODE (inner)) - len - pos; |
| unsignedp = (code == ZERO_EXTRACT); |
| } |
| break; |
| } |
| |
| if (len && pos >= 0 && pos + len <= GET_MODE_BITSIZE (GET_MODE (inner))) |
| { |
| enum machine_mode mode = GET_MODE (SET_SRC (x)); |
| |
| /* For unsigned, we have a choice of a shift followed by an |
| AND or two shifts. Use two shifts for field sizes where the |
| constant might be too large. We assume here that we can |
| always at least get 8-bit constants in an AND insn, which is |
| true for every current RISC. */ |
| |
| if (unsignedp && len <= 8) |
| { |
| SUBST (SET_SRC (x), |
| gen_rtx_combine |
| (AND, mode, |
| gen_rtx_combine (LSHIFTRT, mode, |
| gen_lowpart_for_combine (mode, inner), |
| GEN_INT (pos)), |
| GEN_INT (((HOST_WIDE_INT) 1 << len) - 1))); |
| |
| split = find_split_point (&SET_SRC (x), insn); |
| if (split && split != &SET_SRC (x)) |
| return split; |
| } |
| else |
| { |
| SUBST (SET_SRC (x), |
| gen_rtx_combine |
| (unsignedp ? LSHIFTRT : ASHIFTRT, mode, |
| gen_rtx_combine (ASHIFT, mode, |
| gen_lowpart_for_combine (mode, inner), |
| GEN_INT (GET_MODE_BITSIZE (mode) |
| - len - pos)), |
| GEN_INT (GET_MODE_BITSIZE (mode) - len))); |
| |
| split = find_split_point (&SET_SRC (x), insn); |
| if (split && split != &SET_SRC (x)) |
| return split; |
| } |
| } |
| |
| /* See if this is a simple operation with a constant as the second |
| operand. It might be that this constant is out of range and hence |
| could be used as a split point. */ |
| if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2' |
| || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c' |
| || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<') |
| && CONSTANT_P (XEXP (SET_SRC (x), 1)) |
| && (GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (x), 0))) == 'o' |
| || (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG |
| && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (SET_SRC (x), 0)))) |
| == 'o')))) |
| return &XEXP (SET_SRC (x), 1); |
| |
| /* Finally, see if this is a simple operation with its first operand |
| not in a register. The operation might require this operand in a |
| register, so return it as a split point. We can always do this |
| because if the first operand were another operation, we would have |
| already found it as a split point. */ |
| if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2' |
| || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c' |
| || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<' |
| || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '1') |
| && ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode)) |
| return &XEXP (SET_SRC (x), 0); |
| |
| return 0; |
| |
| case AND: |
| case IOR: |
| /* We write NOR as (and (not A) (not B)), but if we don't have a NOR, |
| it is better to write this as (not (ior A B)) so we can split it. |
| Similarly for IOR. */ |
| if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT) |
| { |
| SUBST (*loc, |
| gen_rtx_combine (NOT, GET_MODE (x), |
| gen_rtx_combine (code == IOR ? AND : IOR, |
| GET_MODE (x), |
| XEXP (XEXP (x, 0), 0), |
| XEXP (XEXP (x, 1), 0)))); |
| return find_split_point (loc, insn); |
| } |
| |
| /* Many RISC machines have a large set of logical insns. If the |
| second operand is a NOT, put it first so we will try to split the |
| other operand first. */ |
| if (GET_CODE (XEXP (x, 1)) == NOT) |
| { |
| rtx tem = XEXP (x, 0); |
| SUBST (XEXP (x, 0), XEXP (x, 1)); |
| SUBST (XEXP (x, 1), tem); |
| } |
| break; |
| } |
| |
| /* Otherwise, select our actions depending on our rtx class. */ |
| switch (GET_RTX_CLASS (code)) |
| { |
| case 'b': /* This is ZERO_EXTRACT and SIGN_EXTRACT. */ |
| case '3': |
| split = find_split_point (&XEXP (x, 2), insn); |
| if (split) |
| return split; |
| /* ... fall through ... */ |
| case '2': |
| case 'c': |
| case '<': |
| split = find_split_point (&XEXP (x, 1), insn); |
| if (split) |
| return split; |
| /* ... fall through ... */ |
| case '1': |
| /* Some machines have (and (shift ...) ...) insns. If X is not |
| an AND, but XEXP (X, 0) is, use it as our split point. */ |
| if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND) |
| return &XEXP (x, 0); |
| |
| split = find_split_point (&XEXP (x, 0), insn); |
| if (split) |
| return split; |
| return loc; |
| } |
| |
| /* Otherwise, we don't have a split point. */ |
| return 0; |
| } |
| |
| /* Throughout X, replace FROM with TO, and return the result. |
| The result is TO if X is FROM; |
| otherwise the result is X, but its contents may have been modified. |
| If they were modified, a record was made in undobuf so that |
| undo_all will (among other things) return X to its original state. |
| |
| If the number of changes necessary is too much to record to undo, |
| the excess changes are not made, so the result is invalid. |
| The changes already made can still be undone. |
| undobuf.num_undo is incremented for such changes, so by testing that |
| the caller can tell whether the result is valid. |
| |
| `n_occurrences' is incremented each time FROM is replaced. |
| |
| IN_DEST is non-zero if we are processing the SET_DEST of a SET. |
| |
| UNIQUE_COPY is non-zero if each substitution must be unique. We do this |
| by copying if `n_occurrences' is non-zero. */ |
| |
| static rtx |
| subst (x, from, to, in_dest, unique_copy) |
| register rtx x, from, to; |
| int in_dest; |
| int unique_copy; |
| { |
| register enum rtx_code code = GET_CODE (x); |
| enum machine_mode op0_mode = VOIDmode; |
| register char *fmt; |
| register int len, i; |
| rtx new; |
| |
| /* Two expressions are equal if they are identical copies of a shared |
| RTX or if they are both registers with the same register number |
| and mode. */ |
| |
| #define COMBINE_RTX_EQUAL_P(X,Y) \ |
| ((X) == (Y) \ |
| || (GET_CODE (X) == REG && GET_CODE (Y) == REG \ |
| && REGNO (X) == REGNO (Y) && GET_MODE (X) == GET_MODE (Y))) |
| |
| if (! in_dest && COMBINE_RTX_EQUAL_P (x, from)) |
| { |
| n_occurrences++; |
| return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to); |
| } |
| |
| /* If X and FROM are the same register but different modes, they will |
| not have been seen as equal above. However, flow.c will make a |
| LOG_LINKS entry for that case. If we do nothing, we will try to |
| rerecognize our original insn and, when it succeeds, we will |
| delete the feeding insn, which is incorrect. |
| |
| So force this insn not to match in this (rare) case. */ |
| if (! in_dest && code == REG && GET_CODE (from) == REG |
| && REGNO (x) == REGNO (from)) |
| return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx); |
| |
| /* If this is an object, we are done unless it is a MEM or LO_SUM, both |
| of which may contain things that can be combined. */ |
| if (code != MEM && code != LO_SUM && GET_RTX_CLASS (code) == 'o') |
| return x; |
| |
| /* It is possible to have a subexpression appear twice in the insn. |
| Suppose that FROM is a register that appears within TO. |
| Then, after that subexpression has been scanned once by `subst', |
| the second time it is scanned, TO may be found. If we were |
| to scan TO here, we would find FROM within it and create a |
| self-referent rtl structure which is completely wrong. */ |
| if (COMBINE_RTX_EQUAL_P (x, to)) |
| return to; |
| |
| len = GET_RTX_LENGTH (code); |
| fmt = GET_RTX_FORMAT (code); |
| |
| /* We don't need to process a SET_DEST that is a register, CC0, or PC, so |
| set up to skip this common case. All other cases where we want to |
| suppress replacing something inside a SET_SRC are handled via the |
| IN_DEST operand. */ |
| if (code == SET |
| && (GET_CODE (SET_DEST (x)) == REG |
| || GET_CODE (SET_DEST (x)) == CC0 |
| || GET_CODE (SET_DEST (x)) == PC)) |
| fmt = "ie"; |
| |
| /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a |
| constant. */ |
| if (fmt[0] == 'e') |
| op0_mode = GET_MODE (XEXP (x, 0)); |
| |
| for (i = 0; i < len; i++) |
| { |
| if (fmt[i] == 'E') |
| { |
| register int j; |
|