| /* Common subexpression elimination for GNU compiler. |
| Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc. |
| |
| This file is part of GNU CC. |
| |
| GNU CC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU CC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU CC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| |
| #include "config.h" |
| /* Must precede rtl.h for FFS. */ |
| #include <stdio.h> |
| |
| #include "rtl.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "flags.h" |
| #include "real.h" |
| #include "insn-config.h" |
| #include "recog.h" |
| |
| #include <setjmp.h> |
| |
| /* The basic idea of common subexpression elimination is to go |
| through the code, keeping a record of expressions that would |
| have the same value at the current scan point, and replacing |
| expressions encountered with the cheapest equivalent expression. |
| |
| It is too complicated to keep track of the different possibilities |
| when control paths merge; so, at each label, we forget all that is |
| known and start fresh. This can be described as processing each |
| basic block separately. Note, however, that these are not quite |
| the same as the basic blocks found by a later pass and used for |
| data flow analysis and register packing. We do not need to start fresh |
| after a conditional jump instruction if there is no label there. |
| |
| We use two data structures to record the equivalent expressions: |
| a hash table for most expressions, and several vectors together |
| with "quantity numbers" to record equivalent (pseudo) registers. |
| |
| The use of the special data structure for registers is desirable |
| because it is faster. It is possible because registers references |
| contain a fairly small number, the register number, taken from |
| a contiguously allocated series, and two register references are |
| identical if they have the same number. General expressions |
| do not have any such thing, so the only way to retrieve the |
| information recorded on an expression other than a register |
| is to keep it in a hash table. |
| |
| Registers and "quantity numbers": |
| |
| At the start of each basic block, all of the (hardware and pseudo) |
| registers used in the function are given distinct quantity |
| numbers to indicate their contents. During scan, when the code |
| copies one register into another, we copy the quantity number. |
| When a register is loaded in any other way, we allocate a new |
| quantity number to describe the value generated by this operation. |
| `reg_qty' records what quantity a register is currently thought |
| of as containing. |
| |
| All real quantity numbers are greater than or equal to `max_reg'. |
| If register N has not been assigned a quantity, reg_qty[N] will equal N. |
| |
| Quantity numbers below `max_reg' do not exist and none of the `qty_...' |
| variables should be referenced with an index below `max_reg'. |
| |
| We also maintain a bidirectional chain of registers for each |
| quantity number. `qty_first_reg', `qty_last_reg', |
| `reg_next_eqv' and `reg_prev_eqv' hold these chains. |
| |
| The first register in a chain is the one whose lifespan is least local. |
| Among equals, it is the one that was seen first. |
| We replace any equivalent register with that one. |
| |
| If two registers have the same quantity number, it must be true that |
| REG expressions with `qty_mode' must be in the hash table for both |
| registers and must be in the same class. |
| |
| The converse is not true. Since hard registers may be referenced in |
| any mode, two REG expressions might be equivalent in the hash table |
| but not have the same quantity number if the quantity number of one |
| of the registers is not the same mode as those expressions. |
| |
| Constants and quantity numbers |
| |
| When a quantity has a known constant value, that value is stored |
| in the appropriate element of qty_const. This is in addition to |
| putting the constant in the hash table as is usual for non-regs. |
| |
| Whether a reg or a constant is preferred is determined by the configuration |
| macro CONST_COSTS and will often depend on the constant value. In any |
| event, expressions containing constants can be simplified, by fold_rtx. |
| |
| When a quantity has a known nearly constant value (such as an address |
| of a stack slot), that value is stored in the appropriate element |
| of qty_const. |
| |
| Integer constants don't have a machine mode. However, cse |
| determines the intended machine mode from the destination |
| of the instruction that moves the constant. The machine mode |
| is recorded in the hash table along with the actual RTL |
| constant expression so that different modes are kept separate. |
| |
| Other expressions: |
| |
| To record known equivalences among expressions in general |
| we use a hash table called `table'. It has a fixed number of buckets |
| that contain chains of `struct table_elt' elements for expressions. |
| These chains connect the elements whose expressions have the same |
| hash codes. |
| |
| Other chains through the same elements connect the elements which |
| currently have equivalent values. |
| |
| Register references in an expression are canonicalized before hashing |
| the expression. This is done using `reg_qty' and `qty_first_reg'. |
| The hash code of a register reference is computed using the quantity |
| number, not the register number. |
| |
| When the value of an expression changes, it is necessary to remove from the |
| hash table not just that expression but all expressions whose values |
| could be different as a result. |
| |
| 1. If the value changing is in memory, except in special cases |
| ANYTHING referring to memory could be changed. That is because |
| nobody knows where a pointer does not point. |
| The function `invalidate_memory' removes what is necessary. |
| |
| The special cases are when the address is constant or is |
| a constant plus a fixed register such as the frame pointer |
| or a static chain pointer. When such addresses are stored in, |
| we can tell exactly which other such addresses must be invalidated |
| due to overlap. `invalidate' does this. |
| All expressions that refer to non-constant |
| memory addresses are also invalidated. `invalidate_memory' does this. |
| |
| 2. If the value changing is a register, all expressions |
| containing references to that register, and only those, |
| must be removed. |
| |
| Because searching the entire hash table for expressions that contain |
| a register is very slow, we try to figure out when it isn't necessary. |
| Precisely, this is necessary only when expressions have been |
| entered in the hash table using this register, and then the value has |
| changed, and then another expression wants to be added to refer to |
| the register's new value. This sequence of circumstances is rare |
| within any one basic block. |
| |
| The vectors `reg_tick' and `reg_in_table' are used to detect this case. |
| reg_tick[i] is incremented whenever a value is stored in register i. |
| reg_in_table[i] holds -1 if no references to register i have been |
| entered in the table; otherwise, it contains the value reg_tick[i] had |
| when the references were entered. If we want to enter a reference |
| and reg_in_table[i] != reg_tick[i], we must scan and remove old references. |
| Until we want to enter a new entry, the mere fact that the two vectors |
| don't match makes the entries be ignored if anyone tries to match them. |
| |
| Registers themselves are entered in the hash table as well as in |
| the equivalent-register chains. However, the vectors `reg_tick' |
| and `reg_in_table' do not apply to expressions which are simple |
| register references. These expressions are removed from the table |
| immediately when they become invalid, and this can be done even if |
| we do not immediately search for all the expressions that refer to |
| the register. |
| |
| A CLOBBER rtx in an instruction invalidates its operand for further |
| reuse. A CLOBBER or SET rtx whose operand is a MEM:BLK |
| invalidates everything that resides in memory. |
| |
| Related expressions: |
| |
| Constant expressions that differ only by an additive integer |
| are called related. When a constant expression is put in |
| the table, the related expression with no constant term |
| is also entered. These are made to point at each other |
| so that it is possible to find out if there exists any |
| register equivalent to an expression related to a given expression. */ |
| |
| /* One plus largest register number used in this function. */ |
| |
| static int max_reg; |
| |
| /* Length of vectors indexed by quantity number. |
| We know in advance we will not need a quantity number this big. */ |
| |
| static int max_qty; |
| |
| /* Next quantity number to be allocated. |
| This is 1 + the largest number needed so far. */ |
| |
| static int next_qty; |
| |
| /* Indexed by quantity number, gives the first (or last) register |
| in the chain of registers that currently contain this quantity. */ |
| |
| static int *qty_first_reg; |
| static int *qty_last_reg; |
| |
| /* Index by quantity number, gives the mode of the quantity. */ |
| |
| static enum machine_mode *qty_mode; |
| |
| /* Indexed by quantity number, gives the rtx of the constant value of the |
| quantity, or zero if it does not have a known value. |
| A sum of the frame pointer (or arg pointer) plus a constant |
| can also be entered here. */ |
| |
| static rtx *qty_const; |
| |
| /* Indexed by qty number, gives the insn that stored the constant value |
| recorded in `qty_const'. */ |
| |
| static rtx *qty_const_insn; |
| |
| /* The next three variables are used to track when a comparison between a |
| quantity and some constant or register has been passed. In that case, we |
| know the results of the comparison in case we see it again. These variables |
| record a comparison that is known to be true. */ |
| |
| /* Indexed by qty number, gives the rtx code of a comparison with a known |
| result involving this quantity. If none, it is UNKNOWN. */ |
| static enum rtx_code *qty_comparison_code; |
| |
| /* Indexed by qty number, gives the constant being compared against in a |
| comparison of known result. If no such comparison, it is undefined. |
| If the comparison is not with a constant, it is zero. */ |
| |
| static rtx *qty_comparison_const; |
| |
| /* Indexed by qty number, gives the quantity being compared against in a |
| comparison of known result. If no such comparison, if it undefined. |
| If the comparison is not with a register, it is -1. */ |
| |
| static int *qty_comparison_qty; |
| |
| #ifdef HAVE_cc0 |
| /* For machines that have a CC0, we do not record its value in the hash |
| table since its use is guaranteed to be the insn immediately following |
| its definition and any other insn is presumed to invalidate it. |
| |
| Instead, we store below the value last assigned to CC0. If it should |
| happen to be a constant, it is stored in preference to the actual |
| assigned value. In case it is a constant, we store the mode in which |
| the constant should be interpreted. */ |
| |
| static rtx prev_insn_cc0; |
| static enum machine_mode prev_insn_cc0_mode; |
| #endif |
| |
| /* Previous actual insn. 0 if at first insn of basic block. */ |
| |
| static rtx prev_insn; |
| |
| /* Insn being scanned. */ |
| |
| static rtx this_insn; |
| |
| /* Index by register number, gives the quantity number |
| of the register's current contents. */ |
| |
| static int *reg_qty; |
| |
| /* Index by register number, gives the number of the next (or |
| previous) register in the chain of registers sharing the same |
| value. |
| |
| Or -1 if this register is at the end of the chain. |
| |
| If reg_qty[N] == N, reg_next_eqv[N] is undefined. */ |
| |
| static int *reg_next_eqv; |
| static int *reg_prev_eqv; |
| |
| /* Index by register number, gives the number of times |
| that register has been altered in the current basic block. */ |
| |
| static int *reg_tick; |
| |
| /* Index by register number, gives the reg_tick value at which |
| rtx's containing this register are valid in the hash table. |
| If this does not equal the current reg_tick value, such expressions |
| existing in the hash table are invalid. |
| If this is -1, no expressions containing this register have been |
| entered in the table. */ |
| |
| static int *reg_in_table; |
| |
| /* A HARD_REG_SET containing all the hard registers for which there is |
| currently a REG expression in the hash table. Note the difference |
| from the above variables, which indicate if the REG is mentioned in some |
| expression in the table. */ |
| |
| static HARD_REG_SET hard_regs_in_table; |
| |
| /* A HARD_REG_SET containing all the hard registers that are invalidated |
| by a CALL_INSN. */ |
| |
| static HARD_REG_SET regs_invalidated_by_call; |
| |
| /* Two vectors of ints: |
| one containing max_reg -1's; the other max_reg + 500 (an approximation |
| for max_qty) elements where element i contains i. |
| These are used to initialize various other vectors fast. */ |
| |
| static int *all_minus_one; |
| static int *consec_ints; |
| |
| /* CUID of insn that starts the basic block currently being cse-processed. */ |
| |
| static int cse_basic_block_start; |
| |
| /* CUID of insn that ends the basic block currently being cse-processed. */ |
| |
| static int cse_basic_block_end; |
| |
| /* Vector mapping INSN_UIDs to cuids. |
| The cuids are like uids but increase monotonically always. |
| We use them to see whether a reg is used outside a given basic block. */ |
| |
| static int *uid_cuid; |
| |
| /* Highest UID in UID_CUID. */ |
| static int max_uid; |
| |
| /* Get the cuid of an insn. */ |
| |
| #define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)]) |
| |
| /* Nonzero if cse has altered conditional jump insns |
| in such a way that jump optimization should be redone. */ |
| |
| static int cse_jumps_altered; |
| |
| /* Nonzero if we put a LABEL_REF into the hash table. Since we may have put |
| it into an INSN without a REG_LABEL, we have to rerun jump after CSE |
| to put in the note. */ |
| static int recorded_label_ref; |
| |
| /* canon_hash stores 1 in do_not_record |
| if it notices a reference to CC0, PC, or some other volatile |
| subexpression. */ |
| |
| static int do_not_record; |
| |
| #ifdef LOAD_EXTEND_OP |
| |
| /* Scratch rtl used when looking for load-extended copy of a MEM. */ |
| static rtx memory_extend_rtx; |
| #endif |
| |
| /* canon_hash stores 1 in hash_arg_in_memory |
| if it notices a reference to memory within the expression being hashed. */ |
| |
| static int hash_arg_in_memory; |
| |
| /* canon_hash stores 1 in hash_arg_in_struct |
| if it notices a reference to memory that's part of a structure. */ |
| |
| static int hash_arg_in_struct; |
| |
| /* The hash table contains buckets which are chains of `struct table_elt's, |
| each recording one expression's information. |
| That expression is in the `exp' field. |
| |
| Those elements with the same hash code are chained in both directions |
| through the `next_same_hash' and `prev_same_hash' fields. |
| |
| Each set of expressions with equivalent values |
| are on a two-way chain through the `next_same_value' |
| and `prev_same_value' fields, and all point with |
| the `first_same_value' field at the first element in |
| that chain. The chain is in order of increasing cost. |
| Each element's cost value is in its `cost' field. |
| |
| The `in_memory' field is nonzero for elements that |
| involve any reference to memory. These elements are removed |
| whenever a write is done to an unidentified location in memory. |
| To be safe, we assume that a memory address is unidentified unless |
| the address is either a symbol constant or a constant plus |
| the frame pointer or argument pointer. |
| |
| The `in_struct' field is nonzero for elements that |
| involve any reference to memory inside a structure or array. |
| |
| The `related_value' field is used to connect related expressions |
| (that differ by adding an integer). |
| The related expressions are chained in a circular fashion. |
| `related_value' is zero for expressions for which this |
| chain is not useful. |
| |
| The `cost' field stores the cost of this element's expression. |
| |
| The `is_const' flag is set if the element is a constant (including |
| a fixed address). |
| |
| The `flag' field is used as a temporary during some search routines. |
| |
| The `mode' field is usually the same as GET_MODE (`exp'), but |
| if `exp' is a CONST_INT and has no machine mode then the `mode' |
| field is the mode it was being used as. Each constant is |
| recorded separately for each mode it is used with. */ |
| |
| |
| struct table_elt |
| { |
| rtx exp; |
| struct table_elt *next_same_hash; |
| struct table_elt *prev_same_hash; |
| struct table_elt *next_same_value; |
| struct table_elt *prev_same_value; |
| struct table_elt *first_same_value; |
| struct table_elt *related_value; |
| int cost; |
| enum machine_mode mode; |
| char in_memory; |
| char in_struct; |
| char is_const; |
| char flag; |
| }; |
| |
| /* We don't want a lot of buckets, because we rarely have very many |
| things stored in the hash table, and a lot of buckets slows |
| down a lot of loops that happen frequently. */ |
| #define NBUCKETS 31 |
| |
| /* Compute hash code of X in mode M. Special-case case where X is a pseudo |
| register (hard registers may require `do_not_record' to be set). */ |
| |
| #define HASH(X, M) \ |
| (GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER \ |
| ? (((unsigned) REG << 7) + (unsigned) reg_qty[REGNO (X)]) % NBUCKETS \ |
| : canon_hash (X, M) % NBUCKETS) |
| |
| /* Determine whether register number N is considered a fixed register for CSE. |
| It is desirable to replace other regs with fixed regs, to reduce need for |
| non-fixed hard regs. |
| A reg wins if it is either the frame pointer or designated as fixed, |
| but not if it is an overlapping register. */ |
| #ifdef OVERLAPPING_REGNO_P |
| #define FIXED_REGNO_P(N) \ |
| (((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \ |
| || fixed_regs[N] || global_regs[N]) \ |
| && ! OVERLAPPING_REGNO_P ((N))) |
| #else |
| #define FIXED_REGNO_P(N) \ |
| ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \ |
| || fixed_regs[N] || global_regs[N]) |
| #endif |
| |
| /* Compute cost of X, as stored in the `cost' field of a table_elt. Fixed |
| hard registers and pointers into the frame are the cheapest with a cost |
| of 0. Next come pseudos with a cost of one and other hard registers with |
| a cost of 2. Aside from these special cases, call `rtx_cost'. */ |
| |
| #define CHEAP_REGNO(N) \ |
| ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \ |
| || (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM \ |
| || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \ |
| || ((N) < FIRST_PSEUDO_REGISTER \ |
| && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS)) |
| |
| /* A register is cheap if it is a user variable assigned to the register |
| or if its register number always corresponds to a cheap register. */ |
| |
| #define CHEAP_REG(N) \ |
| ((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER) \ |
| || CHEAP_REGNO (REGNO (N))) |
| |
| #define COST(X) \ |
| (GET_CODE (X) == REG \ |
| ? (CHEAP_REG (X) ? 0 \ |
| : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \ |
| : 2) \ |
| : notreg_cost(X)) |
| |
| /* Determine if the quantity number for register X represents a valid index |
| into the `qty_...' variables. */ |
| |
| #define REGNO_QTY_VALID_P(N) (reg_qty[N] != (N)) |
| |
| static struct table_elt *table[NBUCKETS]; |
| |
| /* Chain of `struct table_elt's made so far for this function |
| but currently removed from the table. */ |
| |
| static struct table_elt *free_element_chain; |
| |
| /* Number of `struct table_elt' structures made so far for this function. */ |
| |
| static int n_elements_made; |
| |
| /* Maximum value `n_elements_made' has had so far in this compilation |
| for functions previously processed. */ |
| |
| static int max_elements_made; |
| |
| /* Surviving equivalence class when two equivalence classes are merged |
| by recording the effects of a jump in the last insn. Zero if the |
| last insn was not a conditional jump. */ |
| |
| static struct table_elt *last_jump_equiv_class; |
| |
| /* Set to the cost of a constant pool reference if one was found for a |
| symbolic constant. If this was found, it means we should try to |
| convert constants into constant pool entries if they don't fit in |
| the insn. */ |
| |
| static int constant_pool_entries_cost; |
| |
| /* Bits describing what kind of values in memory must be invalidated |
| for a particular instruction. If all three bits are zero, |
| no memory refs need to be invalidated. Each bit is more powerful |
| than the preceding ones, and if a bit is set then the preceding |
| bits are also set. |
| |
| Here is how the bits are set: |
| Pushing onto the stack invalidates only the stack pointer, |
| writing at a fixed address invalidates only variable addresses, |
| writing in a structure element at variable address |
| invalidates all but scalar variables, |
| and writing in anything else at variable address invalidates everything. */ |
| |
| struct write_data |
| { |
| int sp : 1; /* Invalidate stack pointer. */ |
| int var : 1; /* Invalidate variable addresses. */ |
| int nonscalar : 1; /* Invalidate all but scalar variables. */ |
| int all : 1; /* Invalidate all memory refs. */ |
| }; |
| |
| /* Define maximum length of a branch path. */ |
| |
| #define PATHLENGTH 10 |
| |
| /* This data describes a block that will be processed by cse_basic_block. */ |
| |
| struct cse_basic_block_data { |
| /* Lowest CUID value of insns in block. */ |
| int low_cuid; |
| /* Highest CUID value of insns in block. */ |
| int high_cuid; |
| /* Total number of SETs in block. */ |
| int nsets; |
| /* Last insn in the block. */ |
| rtx last; |
| /* Size of current branch path, if any. */ |
| int path_size; |
| /* Current branch path, indicating which branches will be taken. */ |
| struct branch_path { |
| /* The branch insn. */ |
| rtx branch; |
| /* Whether it should be taken or not. AROUND is the same as taken |
| except that it is used when the destination label is not preceded |
| by a BARRIER. */ |
| enum taken {TAKEN, NOT_TAKEN, AROUND} status; |
| } path[PATHLENGTH]; |
| }; |
| |
| /* Nonzero if X has the form (PLUS frame-pointer integer). We check for |
| virtual regs here because the simplify_*_operation routines are called |
| by integrate.c, which is called before virtual register instantiation. */ |
| |
| #define FIXED_BASE_PLUS_P(X) \ |
| ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \ |
| || (X) == arg_pointer_rtx \ |
| || (X) == virtual_stack_vars_rtx \ |
| || (X) == virtual_incoming_args_rtx \ |
| || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ |
| && (XEXP (X, 0) == frame_pointer_rtx \ |
| || XEXP (X, 0) == hard_frame_pointer_rtx \ |
| || XEXP (X, 0) == arg_pointer_rtx \ |
| || XEXP (X, 0) == virtual_stack_vars_rtx \ |
| || XEXP (X, 0) == virtual_incoming_args_rtx))) |
| |
| /* Similar, but also allows reference to the stack pointer. |
| |
| This used to include FIXED_BASE_PLUS_P, however, we can't assume that |
| arg_pointer_rtx by itself is nonzero, because on at least one machine, |
| the i960, the arg pointer is zero when it is unused. */ |
| |
| #define NONZERO_BASE_PLUS_P(X) \ |
| ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \ |
| || (X) == virtual_stack_vars_rtx \ |
| || (X) == virtual_incoming_args_rtx \ |
| || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ |
| && (XEXP (X, 0) == frame_pointer_rtx \ |
| || XEXP (X, 0) == hard_frame_pointer_rtx \ |
| || XEXP (X, 0) == arg_pointer_rtx \ |
| || XEXP (X, 0) == virtual_stack_vars_rtx \ |
| || XEXP (X, 0) == virtual_incoming_args_rtx)) \ |
| || (X) == stack_pointer_rtx \ |
| || (X) == virtual_stack_dynamic_rtx \ |
| || (X) == virtual_outgoing_args_rtx \ |
| || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ |
| && (XEXP (X, 0) == stack_pointer_rtx \ |
| || XEXP (X, 0) == virtual_stack_dynamic_rtx \ |
| || XEXP (X, 0) == virtual_outgoing_args_rtx))) |
| |
| static int notreg_cost PROTO((rtx)); |
| static void new_basic_block PROTO((void)); |
| static void make_new_qty PROTO((int)); |
| static void make_regs_eqv PROTO((int, int)); |
| static void delete_reg_equiv PROTO((int)); |
| static int mention_regs PROTO((rtx)); |
| static int insert_regs PROTO((rtx, struct table_elt *, int)); |
| static void free_element PROTO((struct table_elt *)); |
| static void remove_from_table PROTO((struct table_elt *, unsigned)); |
| static struct table_elt *get_element PROTO((void)); |
| static struct table_elt *lookup PROTO((rtx, unsigned, enum machine_mode)), |
| *lookup_for_remove PROTO((rtx, unsigned, enum machine_mode)); |
| static rtx lookup_as_function PROTO((rtx, enum rtx_code)); |
| static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned, |
| enum machine_mode)); |
| static void merge_equiv_classes PROTO((struct table_elt *, |
| struct table_elt *)); |
| static void invalidate PROTO((rtx, enum machine_mode)); |
| static void remove_invalid_refs PROTO((int)); |
| static void rehash_using_reg PROTO((rtx)); |
| static void invalidate_memory PROTO((struct write_data *)); |
| static void invalidate_for_call PROTO((void)); |
| static rtx use_related_value PROTO((rtx, struct table_elt *)); |
| static unsigned canon_hash PROTO((rtx, enum machine_mode)); |
| static unsigned safe_hash PROTO((rtx, enum machine_mode)); |
| static int exp_equiv_p PROTO((rtx, rtx, int, int)); |
| static void set_nonvarying_address_components PROTO((rtx, int, rtx *, |
| HOST_WIDE_INT *, |
| HOST_WIDE_INT *)); |
| static int refers_to_p PROTO((rtx, rtx)); |
| static int refers_to_mem_p PROTO((rtx, rtx, HOST_WIDE_INT, |
| HOST_WIDE_INT)); |
| static int cse_rtx_addr_varies_p PROTO((rtx)); |
| static rtx canon_reg PROTO((rtx, rtx)); |
| static void find_best_addr PROTO((rtx, rtx *)); |
| static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *, |
| enum machine_mode *, |
| enum machine_mode *)); |
| static rtx cse_gen_binary PROTO((enum rtx_code, enum machine_mode, |
| rtx, rtx)); |
| static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode, |
| rtx, rtx)); |
| static rtx fold_rtx PROTO((rtx, rtx)); |
| static rtx equiv_constant PROTO((rtx)); |
| static void record_jump_equiv PROTO((rtx, int)); |
| static void record_jump_cond PROTO((enum rtx_code, enum machine_mode, |
| rtx, rtx, int)); |
| static void cse_insn PROTO((rtx, int)); |
| static void note_mem_written PROTO((rtx, struct write_data *)); |
| static void invalidate_from_clobbers PROTO((struct write_data *, rtx)); |
| static rtx cse_process_notes PROTO((rtx, rtx)); |
| static void cse_around_loop PROTO((rtx)); |
| static void invalidate_skipped_set PROTO((rtx, rtx)); |
| static void invalidate_skipped_block PROTO((rtx)); |
| static void cse_check_loop_start PROTO((rtx, rtx)); |
| static void cse_set_around_loop PROTO((rtx, rtx, rtx)); |
| static rtx cse_basic_block PROTO((rtx, rtx, struct branch_path *, int)); |
| static void count_reg_usage PROTO((rtx, int *, rtx, int)); |
| |
| extern int rtx_equal_function_value_matters; |
| |
| /* Return an estimate of the cost of computing rtx X. |
| One use is in cse, to decide which expression to keep in the hash table. |
| Another is in rtl generation, to pick the cheapest way to multiply. |
| Other uses like the latter are expected in the future. */ |
| |
| /* Internal function, to compute cost when X is not a register; called |
| from COST macro to keep it simple. */ |
| |
| static int |
| notreg_cost (x) |
| rtx x; |
| { |
| return ((GET_CODE (x) == SUBREG |
| && GET_CODE (SUBREG_REG (x)) == REG |
| && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT |
| && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT |
| && (GET_MODE_SIZE (GET_MODE (x)) |
| < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) |
| && subreg_lowpart_p (x) |
| && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)), |
| GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))) |
| ? (CHEAP_REG (SUBREG_REG (x)) ? 0 |
| : (REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER ? 1 |
| : 2)) |
| : rtx_cost (x, SET) * 2); |
| } |
| |
| /* Return the right cost to give to an operation |
| to make the cost of the corresponding register-to-register instruction |
| N times that of a fast register-to-register instruction. */ |
| |
| #define COSTS_N_INSNS(N) ((N) * 4 - 2) |
| |
| int |
| rtx_cost (x, outer_code) |
| rtx x; |
| enum rtx_code outer_code; |
| { |
| register int i, j; |
| register enum rtx_code code; |
| register char *fmt; |
| register int total; |
| |
| if (x == 0) |
| return 0; |
| |
| /* Compute the default costs of certain things. |
| Note that RTX_COSTS can override the defaults. */ |
| |
| code = GET_CODE (x); |
| switch (code) |
| { |
| case MULT: |
| /* Count multiplication by 2**n as a shift, |
| because if we are considering it, we would output it as a shift. */ |
| if (GET_CODE (XEXP (x, 1)) == CONST_INT |
| && exact_log2 (INTVAL (XEXP (x, 1))) >= 0) |
| total = 2; |
| else |
| total = COSTS_N_INSNS (5); |
| break; |
| case DIV: |
| case UDIV: |
| case MOD: |
| case UMOD: |
| total = COSTS_N_INSNS (7); |
| break; |
| case USE: |
| /* Used in loop.c and combine.c as a marker. */ |
| total = 0; |
| break; |
| case ASM_OPERANDS: |
| /* We don't want these to be used in substitutions because |
| we have no way of validating the resulting insn. So assign |
| anything containing an ASM_OPERANDS a very high cost. */ |
| total = 1000; |
| break; |
| default: |
| total = 2; |
| } |
| |
| switch (code) |
| { |
| case REG: |
| return ! CHEAP_REG (x); |
| |
| case SUBREG: |
| /* If we can't tie these modes, make this expensive. The larger |
| the mode, the more expensive it is. */ |
| if (! MODES_TIEABLE_P (GET_MODE (x), GET_MODE (SUBREG_REG (x)))) |
| return COSTS_N_INSNS (2 |
| + GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD); |
| return 2; |
| #ifdef RTX_COSTS |
| RTX_COSTS (x, code, outer_code); |
| #endif |
| CONST_COSTS (x, code, outer_code); |
| } |
| |
| /* Sum the costs of the sub-rtx's, plus cost of this operation, |
| which is already in total. */ |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| if (fmt[i] == 'e') |
| total += rtx_cost (XEXP (x, i), code); |
| else if (fmt[i] == 'E') |
| for (j = 0; j < XVECLEN (x, i); j++) |
| total += rtx_cost (XVECEXP (x, i, j), code); |
| |
| return total; |
| } |
| |
| /* Clear the hash table and initialize each register with its own quantity, |
| for a new basic block. */ |
| |
| static void |
| new_basic_block () |
| { |
| register int i; |
| |
| next_qty = max_reg; |
| |
| bzero ((char *) reg_tick, max_reg * sizeof (int)); |
| |
| bcopy ((char *) all_minus_one, (char *) reg_in_table, |
| max_reg * sizeof (int)); |
| bcopy ((char *) consec_ints, (char *) reg_qty, max_reg * sizeof (int)); |
| CLEAR_HARD_REG_SET (hard_regs_in_table); |
| |
| /* The per-quantity values used to be initialized here, but it is |
| much faster to initialize each as it is made in `make_new_qty'. */ |
| |
| for (i = 0; i < NBUCKETS; i++) |
| { |
| register struct table_elt *this, *next; |
| for (this = table[i]; this; this = next) |
| { |
| next = this->next_same_hash; |
| free_element (this); |
| } |
| } |
| |
| bzero ((char *) table, sizeof table); |
| |
| prev_insn = 0; |
| |
| #ifdef HAVE_cc0 |
| prev_insn_cc0 = 0; |
| #endif |
| } |
| |
| /* Say that register REG contains a quantity not in any register before |
| and initialize that quantity. */ |
| |
| static void |
| make_new_qty (reg) |
| register int reg; |
| { |
| register int q; |
| |
| if (next_qty >= max_qty) |
| abort (); |
| |
| q = reg_qty[reg] = next_qty++; |
| qty_first_reg[q] = reg; |
| qty_last_reg[q] = reg; |
| qty_const[q] = qty_const_insn[q] = 0; |
| qty_comparison_code[q] = UNKNOWN; |
| |
| reg_next_eqv[reg] = reg_prev_eqv[reg] = -1; |
| } |
| |
| /* Make reg NEW equivalent to reg OLD. |
| OLD is not changing; NEW is. */ |
| |
| static void |
| make_regs_eqv (new, old) |
| register int new, old; |
| { |
| register int lastr, firstr; |
| register int q = reg_qty[old]; |
| |
| /* Nothing should become eqv until it has a "non-invalid" qty number. */ |
| if (! REGNO_QTY_VALID_P (old)) |
| abort (); |
| |
| reg_qty[new] = q; |
| firstr = qty_first_reg[q]; |
| lastr = qty_last_reg[q]; |
| |
| /* Prefer fixed hard registers to anything. Prefer pseudo regs to other |
| hard regs. Among pseudos, if NEW will live longer than any other reg |
| of the same qty, and that is beyond the current basic block, |
| make it the new canonical replacement for this qty. */ |
| if (! (firstr < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (firstr)) |
| /* Certain fixed registers might be of the class NO_REGS. This means |
| that not only can they not be allocated by the compiler, but |
| they cannot be used in substitutions or canonicalizations |
| either. */ |
| && (new >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new) != NO_REGS) |
| && ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new)) |
| || (new >= FIRST_PSEUDO_REGISTER |
| && (firstr < FIRST_PSEUDO_REGISTER |
| || ((uid_cuid[REGNO_LAST_UID (new)] > cse_basic_block_end |
| || (uid_cuid[REGNO_FIRST_UID (new)] |
| < cse_basic_block_start)) |
| && (uid_cuid[REGNO_LAST_UID (new)] |
| > uid_cuid[REGNO_LAST_UID (firstr)])))))) |
| { |
| reg_prev_eqv[firstr] = new; |
| reg_next_eqv[new] = firstr; |
| reg_prev_eqv[new] = -1; |
| qty_first_reg[q] = new; |
| } |
| else |
| { |
| /* If NEW is a hard reg (known to be non-fixed), insert at end. |
| Otherwise, insert before any non-fixed hard regs that are at the |
| end. Registers of class NO_REGS cannot be used as an |
| equivalent for anything. */ |
| while (lastr < FIRST_PSEUDO_REGISTER && reg_prev_eqv[lastr] >= 0 |
| && (REGNO_REG_CLASS (lastr) == NO_REGS || ! FIXED_REGNO_P (lastr)) |
| && new >= FIRST_PSEUDO_REGISTER) |
| lastr = reg_prev_eqv[lastr]; |
| reg_next_eqv[new] = reg_next_eqv[lastr]; |
| if (reg_next_eqv[lastr] >= 0) |
| reg_prev_eqv[reg_next_eqv[lastr]] = new; |
| else |
| qty_last_reg[q] = new; |
| reg_next_eqv[lastr] = new; |
| reg_prev_eqv[new] = lastr; |
| } |
| } |
| |
| /* Remove REG from its equivalence class. */ |
| |
| static void |
| delete_reg_equiv (reg) |
| register int reg; |
| { |
| register int q = reg_qty[reg]; |
| register int p, n; |
| |
| /* If invalid, do nothing. */ |
| if (q == reg) |
| return; |
| |
| p = reg_prev_eqv[reg]; |
| n = reg_next_eqv[reg]; |
| |
| if (n != -1) |
| reg_prev_eqv[n] = p; |
| else |
| qty_last_reg[q] = p; |
| if (p != -1) |
| reg_next_eqv[p] = n; |
| else |
| qty_first_reg[q] = n; |
| |
| reg_qty[reg] = reg; |
| } |
| |
| /* Remove any invalid expressions from the hash table |
| that refer to any of the registers contained in expression X. |
| |
| Make sure that newly inserted references to those registers |
| as subexpressions will be considered valid. |
| |
| mention_regs is not called when a register itself |
| is being stored in the table. |
| |
| Return 1 if we have done something that may have changed the hash code |
| of X. */ |
| |
| static int |
| mention_regs (x) |
| rtx x; |
| { |
| register enum rtx_code code; |
| register int i, j; |
| register char *fmt; |
| register int changed = 0; |
| |
| if (x == 0) |
| return 0; |
| |
| code = GET_CODE (x); |
| if (code == REG) |
| { |
| register int regno = REGNO (x); |
| register int endregno |
| = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1 |
| : HARD_REGNO_NREGS (regno, GET_MODE (x))); |
| int i; |
| |
| for (i = regno; i < endregno; i++) |
| { |
| if (reg_in_table[i] >= 0 && reg_in_table[i] != reg_tick[i]) |
| remove_invalid_refs (i); |
| |
| reg_in_table[i] = reg_tick[i]; |
| } |
| |
| return 0; |
| } |
| |
| /* If X is a comparison or a COMPARE and either operand is a register |
| that does not have a quantity, give it one. This is so that a later |
| call to record_jump_equiv won't cause X to be assigned a different |
| hash code and not found in the table after that call. |
| |
| It is not necessary to do this here, since rehash_using_reg can |
| fix up the table later, but doing this here eliminates the need to |
| call that expensive function in the most common case where the only |
| use of the register is in the comparison. */ |
| |
| if (code == COMPARE || GET_RTX_CLASS (code) == '<') |
| { |
| if (GET_CODE (XEXP (x, 0)) == REG |
| && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))) |
| if (insert_regs (XEXP (x, 0), NULL_PTR, 0)) |
| { |
| rehash_using_reg (XEXP (x, 0)); |
| changed = 1; |
| } |
| |
| if (GET_CODE (XEXP (x, 1)) == REG |
| && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))) |
| if (insert_regs (XEXP (x, 1), NULL_PTR, 0)) |
| { |
| rehash_using_reg (XEXP (x, 1)); |
| changed = 1; |
| } |
| } |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| if (fmt[i] == 'e') |
| changed |= mention_regs (XEXP (x, i)); |
| else if (fmt[i] == 'E') |
| for (j = 0; j < XVECLEN (x, i); j++) |
| changed |= mention_regs (XVECEXP (x, i, j)); |
| |
| return changed; |
| } |
| |
| /* Update the register quantities for inserting X into the hash table |
| with a value equivalent to CLASSP. |
| (If the class does not contain a REG, it is irrelevant.) |
| If MODIFIED is nonzero, X is a destination; it is being modified. |
| Note that delete_reg_equiv should be called on a register |
| before insert_regs is done on that register with MODIFIED != 0. |
| |
| Nonzero value means that elements of reg_qty have changed |
| so X's hash code may be different. */ |
| |
| static int |
| insert_regs (x, classp, modified) |
| rtx x; |
| struct table_elt *classp; |
| int modified; |
| { |
| if (GET_CODE (x) == REG) |
| { |
| register int regno = REGNO (x); |
| |
| /* If REGNO is in the equivalence table already but is of the |
| wrong mode for that equivalence, don't do anything here. */ |
| |
| if (REGNO_QTY_VALID_P (regno) |
| && qty_mode[reg_qty[regno]] != GET_MODE (x)) |
| return 0; |
| |
| if (modified || ! REGNO_QTY_VALID_P (regno)) |
| { |
| if (classp) |
| for (classp = classp->first_same_value; |
| classp != 0; |
| classp = classp->next_same_value) |
| if (GET_CODE (classp->exp) == REG |
| && GET_MODE (classp->exp) == GET_MODE (x)) |
| { |
| make_regs_eqv (regno, REGNO (classp->exp)); |
| return 1; |
| } |
| |
| make_new_qty (regno); |
| qty_mode[reg_qty[regno]] = GET_MODE (x); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* If X is a SUBREG, we will likely be inserting the inner register in the |
| table. If that register doesn't have an assigned quantity number at |
| this point but does later, the insertion that we will be doing now will |
| not be accessible because its hash code will have changed. So assign |
| a quantity number now. */ |
| |
| else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG |
| && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x)))) |
| { |
| insert_regs (SUBREG_REG (x), NULL_PTR, 0); |
| mention_regs (SUBREG_REG (x)); |
| return 1; |
| } |
| else |
| return mention_regs (x); |
| } |
| |
| /* Look in or update the hash table. */ |
| |
| /* Put the element ELT on the list of free elements. */ |
| |
| static void |
| free_element (elt) |
| struct table_elt *elt; |
| { |
| elt->next_same_hash = free_element_chain; |
| free_element_chain = elt; |
| } |
| |
| /* Return an element that is free for use. */ |
| |
| static struct table_elt * |
| get_element () |
| { |
| struct table_elt *elt = free_element_chain; |
| if (elt) |
| { |
| free_element_chain = elt->next_same_hash; |
| return elt; |
| } |
| n_elements_made++; |
| return (struct table_elt *) oballoc (sizeof (struct table_elt)); |
| } |
| |
| /* Remove table element ELT from use in the table. |
| HASH is its hash code, made using the HASH macro. |
| It's an argument because often that is known in advance |
| and we save much time not recomputing it. */ |
| |
| static void |
| remove_from_table (elt, hash) |
| register struct table_elt *elt; |
| unsigned hash; |
| { |
| if (elt == 0) |
| return; |
| |
| /* Mark this element as removed. See cse_insn. */ |
| elt->first_same_value = 0; |
| |
| /* Remove the table element from its equivalence class. */ |
| |
| { |
| register struct table_elt *prev = elt->prev_same_value; |
| register struct table_elt *next = elt->next_same_value; |
| |
| if (next) next->prev_same_value = prev; |
| |
| if (prev) |
| prev->next_same_value = next; |
| else |
| { |
| register struct table_elt *newfirst = next; |
| while (next) |
| { |
| next->first_same_value = newfirst; |
| next = next->next_same_value; |
| } |
| } |
| } |
| |
| /* Remove the table element from its hash bucket. */ |
| |
| { |
| register struct table_elt *prev = elt->prev_same_hash; |
| register struct table_elt *next = elt->next_same_hash; |
| |
| if (next) next->prev_same_hash = prev; |
| |
| if (prev) |
| prev->next_same_hash = next; |
| else if (table[hash] == elt) |
| table[hash] = next; |
| else |
| { |
| /* This entry is not in the proper hash bucket. This can happen |
| when two classes were merged by `merge_equiv_classes'. Search |
| for the hash bucket that it heads. This happens only very |
| rarely, so the cost is acceptable. */ |
| for (hash = 0; hash < NBUCKETS; hash++) |
| if (table[hash] == elt) |
| table[hash] = next; |
| } |
| } |
| |
| /* Remove the table element from its related-value circular chain. */ |
| |
| if (elt->related_value != 0 && elt->related_value != elt) |
| { |
| register struct table_elt *p = elt->related_value; |
| while (p->related_value != elt) |
| p = p->related_value; |
| p->related_value = elt->related_value; |
| if (p->related_value == p) |
| p->related_value = 0; |
| } |
| |
| free_element (elt); |
| } |
| |
| /* Look up X in the hash table and return its table element, |
| or 0 if X is not in the table. |
| |
| MODE is the machine-mode of X, or if X is an integer constant |
| with VOIDmode then MODE is the mode with which X will be used. |
| |
| Here we are satisfied to find an expression whose tree structure |
| looks like X. */ |
| |
| static struct table_elt * |
| lookup (x, hash, mode) |
| rtx x; |
| unsigned hash; |
| enum machine_mode mode; |
| { |
| register struct table_elt *p; |
| |
| for (p = table[hash]; p; p = p->next_same_hash) |
| if (mode == p->mode && ((x == p->exp && GET_CODE (x) == REG) |
| || exp_equiv_p (x, p->exp, GET_CODE (x) != REG, 0))) |
| return p; |
| |
| return 0; |
| } |
| |
| /* Like `lookup' but don't care whether the table element uses invalid regs. |
| Also ignore discrepancies in the machine mode of a register. */ |
| |
| static struct table_elt * |
| lookup_for_remove (x, hash, mode) |
| rtx x; |
| unsigned hash; |
| enum machine_mode mode; |
| { |
| register struct table_elt *p; |
| |
| if (GET_CODE (x) == REG) |
| { |
| int regno = REGNO (x); |
| /* Don't check the machine mode when comparing registers; |
| invalidating (REG:SI 0) also invalidates (REG:DF 0). */ |
| for (p = table[hash]; p; p = p->next_same_hash) |
| if (GET_CODE (p->exp) == REG |
| && REGNO (p->exp) == regno) |
| return p; |
| } |
| else |
| { |
| for (p = table[hash]; p; p = p->next_same_hash) |
| if (mode == p->mode && (x == p->exp || exp_equiv_p (x, p->exp, 0, 0))) |
| return p; |
| } |
| |
| return 0; |
| } |
| |
| /* Look for an expression equivalent to X and with code CODE. |
| If one is found, return that expression. */ |
| |
| static rtx |
| lookup_as_function (x, code) |
| rtx x; |
| enum rtx_code code; |
| { |
| register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, |
| GET_MODE (x)); |
| if (p == 0) |
| return 0; |
| |
| for (p = p->first_same_value; p; p = p->next_same_value) |
| { |
| if (GET_CODE (p->exp) == code |
| /* Make sure this is a valid entry in the table. */ |
| && exp_equiv_p (p->exp, p->exp, 1, 0)) |
| return p->exp; |
| } |
| |
| return 0; |
| } |
| |
| /* Insert X in the hash table, assuming HASH is its hash code |
| and CLASSP is an element of the class it should go in |
| (or 0 if a new class should be made). |
| It is inserted at the proper position to keep the class in |
| the order cheapest first. |
| |
| MODE is the machine-mode of X, or if X is an integer constant |
| with VOIDmode then MODE is the mode with which X will be used. |
| |
| For elements of equal cheapness, the most recent one |
| goes in front, except that the first element in the list |
| remains first unless a cheaper element is added. The order of |
| pseudo-registers does not matter, as canon_reg will be called to |
| find the cheapest when a register is retrieved from the table. |
| |
| The in_memory field in the hash table element is set to 0. |
| The caller must set it nonzero if appropriate. |
| |
| You should call insert_regs (X, CLASSP, MODIFY) before calling here, |
| and if insert_regs returns a nonzero value |
| you must then recompute its hash code before calling here. |
| |
| If necessary, update table showing constant values of quantities. */ |
| |
| #define CHEAPER(X,Y) ((X)->cost < (Y)->cost) |
| |
| static struct table_elt * |
| insert (x, classp, hash, mode) |
| register rtx x; |
| register struct table_elt *classp; |
| unsigned hash; |
| enum machine_mode mode; |
| { |
| register struct table_elt *elt; |
| |
| /* If X is a register and we haven't made a quantity for it, |
| something is wrong. */ |
| if (GET_CODE (x) == REG && ! REGNO_QTY_VALID_P (REGNO (x))) |
| abort (); |
| |
| /* If X is a hard register, show it is being put in the table. */ |
| if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER) |
| { |
| int regno = REGNO (x); |
| int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); |
| int i; |
| |
| for (i = regno; i < endregno; i++) |
| SET_HARD_REG_BIT (hard_regs_in_table, i); |
| } |
| |
| /* If X is a label, show we recorded it. */ |
| if (GET_CODE (x) == LABEL_REF |
| || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS |
| && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)) |
| recorded_label_ref = 1; |
| |
| /* Put an element for X into the right hash bucket. */ |
| |
| elt = get_element (); |
| elt->exp = x; |
| elt->cost = COST (x); |
| elt->next_same_value = 0; |
| elt->prev_same_value = 0; |
| elt->next_same_hash = table[hash]; |
| elt->prev_same_hash = 0; |
| elt->related_value = 0; |
| elt->in_memory = 0; |
| elt->mode = mode; |
| elt->is_const = (CONSTANT_P (x) |
| /* GNU C++ takes advantage of this for `this' |
| (and other const values). */ |
| || (RTX_UNCHANGING_P (x) |
| && GET_CODE (x) == REG |
| && REGNO (x) >= FIRST_PSEUDO_REGISTER) |
| || FIXED_BASE_PLUS_P (x)); |
| |
| if (table[hash]) |
| table[hash]->prev_same_hash = elt; |
| table[hash] = elt; |
| |
| /* Put it into the proper value-class. */ |
| if (classp) |
| { |
| classp = classp->first_same_value; |
| if (CHEAPER (elt, classp)) |
| /* Insert at the head of the class */ |
| { |
| register struct table_elt *p; |
| elt->next_same_value = classp; |
| classp->prev_same_value = elt; |
| elt->first_same_value = elt; |
| |
| for (p = classp; p; p = p->next_same_value) |
| p->first_same_value = elt; |
| } |
| else |
| { |
| /* Insert not at head of the class. */ |
| /* Put it after the last element cheaper than X. */ |
| register struct table_elt *p, *next; |
| for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt); |
| p = next); |
| /* Put it after P and before NEXT. */ |
| elt->next_same_value = next; |
| if (next) |
| next->prev_same_value = elt; |
| elt->prev_same_value = p; |
| p->next_same_value = elt; |
| elt->first_same_value = classp; |
| } |
| } |
| else |
| elt->first_same_value = elt; |
| |
| /* If this is a constant being set equivalent to a register or a register |
| being set equivalent to a constant, note the constant equivalence. |
| |
| If this is a constant, it cannot be equivalent to a different constant, |
| and a constant is the only thing that can be cheaper than a register. So |
| we know the register is the head of the class (before the constant was |
| inserted). |
| |
| If this is a register that is not already known equivalent to a |
| constant, we must check the entire class. |
| |
| If this is a register that is already known equivalent to an insn, |
| update `qty_const_insn' to show that `this_insn' is the latest |
| insn making that quantity equivalent to the constant. */ |
| |
| if (elt->is_const && classp && GET_CODE (classp->exp) == REG |
| && GET_CODE (x) != REG) |
| { |
| qty_const[reg_qty[REGNO (classp->exp)]] |
| = gen_lowpart_if_possible (qty_mode[reg_qty[REGNO (classp->exp)]], x); |
| qty_const_insn[reg_qty[REGNO (classp->exp)]] = this_insn; |
| } |
| |
| else if (GET_CODE (x) == REG && classp && ! qty_const[reg_qty[REGNO (x)]] |
| && ! elt->is_const) |
| { |
| register struct table_elt *p; |
| |
| for (p = classp; p != 0; p = p->next_same_value) |
| { |
| if (p->is_const && GET_CODE (p->exp) != REG) |
| { |
| qty_const[reg_qty[REGNO (x)]] |
| = gen_lowpart_if_possible (GET_MODE (x), p->exp); |
| qty_const_insn[reg_qty[REGNO (x)]] = this_insn; |
| break; |
| } |
| } |
| } |
| |
| else if (GET_CODE (x) == REG && qty_const[reg_qty[REGNO (x)]] |
| && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]) |
| qty_const_insn[reg_qty[REGNO (x)]] = this_insn; |
| |
| /* If this is a constant with symbolic value, |
| and it has a term with an explicit integer value, |
| link it up with related expressions. */ |
| if (GET_CODE (x) == CONST) |
| { |
| rtx subexp = get_related_value (x); |
| unsigned subhash; |
| struct table_elt *subelt, *subelt_prev; |
| |
| if (subexp != 0) |
| { |
| /* Get the integer-free subexpression in the hash table. */ |
| subhash = safe_hash (subexp, mode) % NBUCKETS; |
| subelt = lookup (subexp, subhash, mode); |
| if (subelt == 0) |
| subelt = insert (subexp, NULL_PTR, subhash, mode); |
| /* Initialize SUBELT's circular chain if it has none. */ |
| if (subelt->related_value == 0) |
| subelt->related_value = subelt; |
| /* Find the element in the circular chain that precedes SUBELT. */ |
| subelt_prev = subelt; |
| while (subelt_prev->related_value != subelt) |
| subelt_prev = subelt_prev->related_value; |
| /* Put new ELT into SUBELT's circular chain just before SUBELT. |
| This way the element that follows SUBELT is the oldest one. */ |
| elt->related_value = subelt_prev->related_value; |
| subelt_prev->related_value = elt; |
| } |
| } |
| |
| return elt; |
| } |
| |
| /* Given two equivalence classes, CLASS1 and CLASS2, put all the entries from |
| CLASS2 into CLASS1. This is done when we have reached an insn which makes |
| the two classes equivalent. |
| |
| CLASS1 will be the surviving class; CLASS2 should not be used after this |
| call. |
| |
| Any invalid entries in CLASS2 will not be copied. */ |
| |
| static void |
| merge_equiv_classes (class1, class2) |
| struct table_elt *class1, *class2; |
| { |
| struct table_elt *elt, *next, *new; |
| |
| /* Ensure we start with the head of the classes. */ |
| class1 = class1->first_same_value; |
| class2 = class2->first_same_value; |
| |
| /* If they were already equal, forget it. */ |
| if (class1 == class2) |
| return; |
| |
| for (elt = class2; elt; elt = next) |
| { |
| unsigned hash; |
| rtx exp = elt->exp; |
| enum machine_mode mode = elt->mode; |
| |
| next = elt->next_same_value; |
| |
| /* Remove old entry, make a new one in CLASS1's class. |
| Don't do this for invalid entries as we cannot find their |
| hash code (it also isn't necessary). */ |
| if (GET_CODE (exp) == REG || exp_equiv_p (exp, exp, 1, 0)) |
| { |
| hash_arg_in_memory = 0; |
| hash_arg_in_struct = 0; |
| hash = HASH (exp, mode); |
| |
| if (GET_CODE (exp) == REG) |
| delete_reg_equiv (REGNO (exp)); |
| |
| remove_from_table (elt, hash); |
| |
| if (insert_regs (exp, class1, 0)) |
| { |
| rehash_using_reg (exp); |
| hash = HASH (exp, mode); |
| } |
| new = insert (exp, class1, hash, mode); |
| new->in_memory = hash_arg_in_memory; |
| new->in_struct = hash_arg_in_struct; |
| } |
| } |
| } |
| |
| /* Remove from the hash table, or mark as invalid, |
| all expressions whose values could be altered by storing in X. |
| X is a register, a subreg, or a memory reference with nonvarying address |
| (because, when a memory reference with a varying address is stored in, |
| all memory references are removed by invalidate_memory |
| so specific invalidation is superfluous). |
| FULL_MODE, if not VOIDmode, indicates that this much should be invalidated |
| instead of just the amount indicated by the mode of X. This is only used |
| for bitfield stores into memory. |
| |
| A nonvarying address may be just a register or just |
| a symbol reference, or it may be either of those plus |
| a numeric offset. */ |
| |
| static void |
| invalidate (x, full_mode) |
| rtx x; |
| enum machine_mode full_mode; |
| { |
| register int i; |
| register struct table_elt *p; |
| rtx base; |
| HOST_WIDE_INT start, end; |
| |
| /* If X is a register, dependencies on its contents |
| are recorded through the qty number mechanism. |
| Just change the qty number of the register, |
| mark it as invalid for expressions that refer to it, |
| and remove it itself. */ |
| |
| if (GET_CODE (x) == REG) |
| { |
| register int regno = REGNO (x); |
| register unsigned hash = HASH (x, GET_MODE (x)); |
| |
| /* Remove REGNO from any quantity list it might be on and indicate |
| that it's value might have changed. If it is a pseudo, remove its |
| entry from the hash table. |
| |
| For a hard register, we do the first two actions above for any |
| additional hard registers corresponding to X. Then, if any of these |
| registers are in the table, we must remove any REG entries that |
| overlap these registers. */ |
| |
| delete_reg_equiv (regno); |
| reg_tick[regno]++; |
| |
| if (regno >= FIRST_PSEUDO_REGISTER) |
| { |
| /* Because a register can be referenced in more than one mode, |
| we might have to remove more than one table entry. */ |
| |
| struct table_elt *elt; |
| |
| while (elt = lookup_for_remove (x, hash, GET_MODE (x))) |
| remove_from_table (elt, hash); |
| } |
| else |
| { |
| HOST_WIDE_INT in_table |
| = TEST_HARD_REG_BIT (hard_regs_in_table, regno); |
| int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); |
| int tregno, tendregno; |
| register struct table_elt *p, *next; |
| |
| CLEAR_HARD_REG_BIT (hard_regs_in_table, regno); |
| |
| for (i = regno + 1; i < endregno; i++) |
| { |
| in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, i); |
| CLEAR_HARD_REG_BIT (hard_regs_in_table, i); |
| delete_reg_equiv (i); |
| reg_tick[i]++; |
| } |
| |
| if (in_table) |
| for (hash = 0; hash < NBUCKETS; hash++) |
| for (p = table[hash]; p; p = next) |
| { |
| next = p->next_same_hash; |
| |
| if (GET_CODE (p->exp) != REG |
| || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER) |
| continue; |
| |
| tregno = REGNO (p->exp); |
| tendregno |
| = tregno + HARD_REGNO_NREGS (tregno, GET_MODE (p->exp)); |
| if (tendregno > regno && tregno < endregno) |
| remove_from_table (p, hash); |
| } |
| } |
| |
| return; |
| } |
| |
| if (GET_CODE (x) == SUBREG) |
| { |
| if (GET_CODE (SUBREG_REG (x)) != REG) |
| abort (); |
| invalidate (SUBREG_REG (x), VOIDmode); |
| return; |
| } |
| |
| /* X is not a register; it must be a memory reference with |
| a nonvarying address. Remove all hash table elements |
| that refer to overlapping pieces of memory. */ |
| |
| if (GET_CODE (x) != MEM) |
| abort (); |
| |
| if (full_mode == VOIDmode) |
| full_mode = GET_MODE (x); |
| |
| set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode), |
| &base, &start, &end); |
| |
| for (i = 0; i < NBUCKETS; i++) |
| { |
| register struct table_elt *next; |
| for (p = table[i]; p; p = next) |
| { |
| next = p->next_same_hash; |
| if (refers_to_mem_p (p->exp, base, start, end)) |
| remove_from_table (p, i); |
| } |
| } |
| } |
| |
| /* Remove all expressions that refer to register REGNO, |
| since they are already invalid, and we are about to |
| mark that register valid again and don't want the old |
| expressions to reappear as valid. */ |
| |
| static void |
| remove_invalid_refs (regno) |
| int regno; |
| { |
| register int i; |
| register struct table_elt *p, *next; |
| |
| for (i = 0; i < NBUCKETS; i++) |
| for (p = table[i]; p; p = next) |
| { |
| next = p->next_same_hash; |
| if (GET_CODE (p->exp) != REG |
| && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR)) |
| remove_from_table (p, i); |
| } |
| } |
| |
| /* Recompute the hash codes of any valid entries in the hash table that |
| reference X, if X is a register, or SUBREG_REG (X) if X is a SUBREG. |
| |
| This is called when we make a jump equivalence. */ |
| |
| static void |
| rehash_using_reg (x) |
| rtx x; |
| { |
| int i; |
| struct table_elt *p, *next; |
| unsigned hash; |
| |
| if (GET_CODE (x) == SUBREG) |
| x = SUBREG_REG (x); |
| |
| /* If X is not a register or if the register is known not to be in any |
| valid entries in the table, we have no work to do. */ |
| |
| if (GET_CODE (x) != REG |
| || reg_in_table[REGNO (x)] < 0 |
| || reg_in_table[REGNO (x)] != reg_tick[REGNO (x)]) |
| return; |
| |
| /* Scan all hash chains looking for valid entries that mention X. |
| If we find one and it is in the wrong hash chain, move it. We can skip |
| objects that are registers, since they are handled specially. */ |
| |
| for (i = 0; i < NBUCKETS; i++) |
| for (p = table[i]; p; p = next) |
| { |
| next = p->next_same_hash; |
| if (GET_CODE (p->exp) != REG && reg_mentioned_p (x, p->exp) |
| && exp_equiv_p (p->exp, p->exp, 1, 0) |
| && i != (hash = safe_hash (p->exp, p->mode) % NBUCKETS)) |
| { |
| if (p->next_same_hash) |
| p->next_same_hash->prev_same_hash = p->prev_same_hash; |
| |
| if (p->prev_same_hash) |
| p->prev_same_hash->next_same_hash = p->next_same_hash; |
| else |
| table[i] = p->next_same_hash; |
| |
| p->next_same_hash = table[hash]; |
| p->prev_same_hash = 0; |
| if (table[hash]) |
| table[hash]->prev_same_hash = p; |
| table[hash] = p; |
| } |
| } |
| } |
| |
| /* Remove from the hash table all expressions that reference memory, |
| or some of them as specified by *WRITES. */ |
| |
| static void |
| invalidate_memory (writes) |
| struct write_data *writes; |
| { |
| register int i; |
| register struct table_elt *p, *next; |
| int all = writes->all; |
| int nonscalar = writes->nonscalar; |
| |
| for (i = 0; i < NBUCKETS; i++) |
| for (p = table[i]; p; p = next) |
| { |
| next = p->next_same_hash; |
| if (p->in_memory |
| && (all |
| || (nonscalar && p->in_struct) |
| || cse_rtx_addr_varies_p (p->exp))) |
| remove_from_table (p, i); |
| } |
| } |
| |
| /* Remove from the hash table any expression that is a call-clobbered |
| register. Also update their TICK values. */ |
| |
| static void |
| invalidate_for_call () |
| { |
| int regno, endregno; |
| int i; |
| unsigned hash; |
| struct table_elt *p, *next; |
| int in_table = 0; |
| |
| /* Go through all the hard registers. For each that is clobbered in |
| a CALL_INSN, remove the register from quantity chains and update |
| reg_tick if defined. Also see if any of these registers is currently |
| in the table. */ |
| |
| for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) |
| if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)) |
| { |
| delete_reg_equiv (regno); |
| if (reg_tick[regno] >= 0) |
| reg_tick[regno]++; |
| |
| in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0); |
| } |
| |
| /* In the case where we have no call-clobbered hard registers in the |
| table, we are done. Otherwise, scan the table and remove any |
| entry that overlaps a call-clobbered register. */ |
| |
| if (in_table) |
| for (hash = 0; hash < NBUCKETS; hash++) |
| for (p = table[hash]; p; p = next) |
| { |
| next = p->next_same_hash; |
| |
| if (GET_CODE (p->exp) != REG |
| || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER) |
| continue; |
| |
| regno = REGNO (p->exp); |
| endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (p->exp)); |
| |
| for (i = regno; i < endregno; i++) |
| if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) |
| { |
| remove_from_table (p, hash); |
| break; |
| } |
| } |
| } |
| |
| /* Given an expression X of type CONST, |
| and ELT which is its table entry (or 0 if it |
| is not in the hash table), |
| return an alternate expression for X as a register plus integer. |
| If none can be found, return 0. */ |
| |
| static rtx |
| use_related_value (x, elt) |
| rtx x; |
| struct table_elt *elt; |
| { |
| register struct table_elt *relt = 0; |
| register struct table_elt *p, *q; |
| HOST_WIDE_INT offset; |
| |
| /* First, is there anything related known? |
| If we have a table element, we can tell from that. |
| Otherwise, must look it up. */ |
| |
| if (elt != 0 && elt->related_value != 0) |
| relt = elt; |
| else if (elt == 0 && GET_CODE (x) == CONST) |
| { |
| rtx subexp = get_related_value (x); |
| if (subexp != 0) |
| relt = lookup (subexp, |
| safe_hash (subexp, GET_MODE (subexp)) % NBUCKETS, |
| GET_MODE (subexp)); |
| } |
| |
| if (relt == 0) |
| return 0; |
| |
| /* Search all related table entries for one that has an |
| equivalent register. */ |
| |
| p = relt; |
| while (1) |
| { |
| /* This loop is strange in that it is executed in two different cases. |
| The first is when X is already in the table. Then it is searching |
| the RELATED_VALUE list of X's class (RELT). The second case is when |
| X is not in the table. Then RELT points to a class for the related |
| value. |
| |
| Ensure that, whatever case we are in, that we ignore classes that have |
| the same value as X. */ |
| |
| if (rtx_equal_p (x, p->exp)) |
| q = 0; |
| else |
| for (q = p->first_same_value; q; q = q->next_same_value) |
| if (GET_CODE (q->exp) == REG) |
| break; |
| |
| if (q) |
| break; |
| |
| p = p->related_value; |
| |
| /* We went all the way around, so there is nothing to be found. |
| Alternatively, perhaps RELT was in the table for some other reason |
| and it has no related values recorded. */ |
| if (p == relt || p == 0) |
| break; |
| } |
| |
| if (q == 0) |
| return 0; |
| |
| offset = (get_integer_term (x) - get_integer_term (p->exp)); |
| /* Note: OFFSET may be 0 if P->xexp and X are related by commutativity. */ |
| return plus_constant (q->exp, offset); |
| } |
| |
| /* Hash an rtx. We are careful to make sure the value is never negative. |
| Equivalent registers hash identically. |
| MODE is used in hashing for CONST_INTs only; |
| otherwise the mode of X is used. |
| |
| Store 1 in do_not_record if any subexpression is volatile. |
| |
| Store 1 in hash_arg_in_memory if X contains a MEM rtx |
| which does not have the RTX_UNCHANGING_P bit set. |
| In this case, also store 1 in hash_arg_in_struct |
| if there is a MEM rtx which has the MEM_IN_STRUCT_P bit set. |
| |
| Note that cse_insn knows that the hash code of a MEM expression |
| is just (int) MEM plus the hash code of the address. */ |
| |
| static unsigned |
| canon_hash (x, mode) |
| rtx x; |
| enum machine_mode mode; |
| { |
| register int i, j; |
| register unsigned hash = 0; |
| register enum rtx_code code; |
| register char *fmt; |
| |
| /* repeat is used to turn tail-recursion into iteration. */ |
| repeat: |
| if (x == 0) |
| return hash; |
| |
| code = GET_CODE (x); |
| switch (code) |
| { |
| case REG: |
| { |
| register int regno = REGNO (x); |
| |
| /* On some machines, we can't record any non-fixed hard register, |
| because extending its life will cause reload problems. We |
| consider ap, fp, and sp to be fixed for this purpose. |
| On all machines, we can't record any global registers. */ |
| |
| if (regno < FIRST_PSEUDO_REGISTER |
| && (global_regs[regno] |
| #ifdef SMALL_REGISTER_CLASSES |
| || (SMALL_REGISTER_CLASSES |
| && ! fixed_regs[regno] |
| && regno != FRAME_POINTER_REGNUM |
| && regno != HARD_FRAME_POINTER_REGNUM |
| && regno != ARG_POINTER_REGNUM |
| && regno != STACK_POINTER_REGNUM) |
| #endif |
| )) |
| { |
| do_not_record = 1; |
| return 0; |
| } |
| hash += ((unsigned) REG << 7) + (unsigned) reg_qty[regno]; |
| return hash; |
| } |
| |
| case CONST_INT: |
| { |
| unsigned HOST_WIDE_INT tem = INTVAL (x); |
| hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + tem; |
| return hash; |
| } |
| |
| case CONST_DOUBLE: |
| /* This is like the general case, except that it only counts |
| the integers representing the constant. */ |
| hash += (unsigned) code + (unsigned) GET_MODE (x); |
| if (GET_MODE (x) != VOIDmode) |
| for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++) |
| { |
| unsigned tem = XINT (x, i); |
| hash += tem; |
| } |
| else |
| hash += ((unsigned) CONST_DOUBLE_LOW (x) |
| + (unsigned) CONST_DOUBLE_HIGH (x)); |
| return hash; |
| |
| /* Assume there is only one rtx object for any given label. */ |
| case LABEL_REF: |
| hash |
| += ((unsigned) LABEL_REF << 7) + (unsigned HOST_WIDE_INT) XEXP (x, 0); |
| return hash; |
| |
| case SYMBOL_REF: |
| hash |
| += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XSTR (x, 0); |
| return hash; |
| |
| case MEM: |
| if (MEM_VOLATILE_P (x)) |
| { |
| do_not_record = 1; |
| return 0; |
| } |
| if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0))) |
| { |
| hash_arg_in_memory = 1; |
| if (MEM_IN_STRUCT_P (x)) hash_arg_in_struct = 1; |
| } |
| /* Now that we have already found this special case, |
| might as well speed it up as much as possible. */ |
| hash += (unsigned) MEM; |
| x = XEXP (x, 0); |
| goto repeat; |
| |
| case PRE_DEC: |
| case PRE_INC: |
| case POST_DEC: |
| case POST_INC: |
| case PC: |
| case CC0: |
| case CALL: |
| case UNSPEC_VOLATILE: |
| do_not_record = 1; |
| return 0; |
| |
| case ASM_OPERANDS: |
| if (MEM_VOLATILE_P (x)) |
| { |
| do_not_record = 1; |
| return 0; |
| } |
| } |
| |
| i = GET_RTX_LENGTH (code) - 1; |
| hash += (unsigned) code + (unsigned) GET_MODE (x); |
| fmt = GET_RTX_FORMAT (code); |
| for (; i >= 0; i--) |
| { |
| if (fmt[i] == 'e') |
| { |
| rtx tem = XEXP (x, i); |
| |
| /* If we are about to do the last recursive call |
| needed at this level, change it into iteration. |
| This function is called enough to be worth it. */ |
| if (i == 0) |
| { |
| x = tem; |
| goto repeat; |
| } |
| hash += canon_hash (tem, 0); |
| } |
| else if (fmt[i] == 'E') |
| for (j = 0; j < XVECLEN (x, i); j++) |
| hash += canon_hash (XVECEXP (x, i, j), 0); |
| else if (fmt[i] == 's') |
| { |
| register unsigned char *p = (unsigned char *) XSTR (x, i); |
| if (p) |
| while (*p) |
| hash += *p++; |
| } |
| else if (fmt[i] == 'i') |
| { |
| register unsigned tem = XINT (x, i); |
| hash += tem; |
| } |
| else |
| abort (); |
| } |
| return hash; |
| } |
| |
| /* Like canon_hash but with no side effects. */ |
| |
| static unsigned |
| safe_hash (x, mode) |
| rtx x; |
| enum machine_mode mode; |
| { |
| int save_do_not_record = do_not_record; |
| int save_hash_arg_in_memory = hash_arg_in_memory; |
| int save_hash_arg_in_struct = hash_arg_in_struct; |
| unsigned hash = canon_hash (x, mode); |
| hash_arg_in_memory = save_hash_arg_in_memory; |
| hash_arg_in_struct = save_hash_arg_in_struct; |
| do_not_record = save_do_not_record; |
| return hash; |
| } |
| |
| /* Return 1 iff X and Y would canonicalize into the same thing, |
| without actually constructing the canonicalization of either one. |
| If VALIDATE is nonzero, |
| we assume X is an expression being processed from the rtl |
| and Y was found in the hash table. We check register refs |
| in Y for being marked as valid. |
| |
| If EQUAL_VALUES is nonzero, we allow a register to match a constant value |
| that is known to be in the register. Ordinarily, we don't allow them |
| to match, because letting them match would cause unpredictable results |
| in all the places that search a hash table chain for an equivalent |
| for a given value. A possible equivalent that has different structure |
| has its hash code computed from different data. Whether the hash code |
| is the same as that of the the given value is pure luck. */ |
| |
| static int |
| exp_equiv_p (x, y, validate, equal_values) |
| rtx x, y; |
| int validate; |
| int equal_values; |
| { |
| register int i, j; |
| register enum rtx_code code; |
| register char *fmt; |
| |
| /* Note: it is incorrect to assume an expression is equivalent to itself |
| if VALIDATE is nonzero. */ |
| if (x == y && !validate) |
| return 1; |
| if (x == 0 || y == 0) |
| return x == y; |
| |
| code = GET_CODE (x); |
| if (code != GET_CODE (y)) |
| { |
| if (!equal_values) |
| return 0; |
| |
| /* If X is a constant and Y is a register or vice versa, they may be |
| equivalent. We only have to validate if Y is a register. */ |
| if (CONSTANT_P (x) && GET_CODE (y) == REG |
| && REGNO_QTY_VALID_P (REGNO (y)) |
| && GET_MODE (y) == qty_mode[reg_qty[REGNO (y)]] |
| && rtx_equal_p (x, qty_const[reg_qty[REGNO (y)]]) |
| && (! validate || reg_in_table[REGNO (y)] == reg_tick[REGNO (y)])) |
| return 1; |
| |
| if (CONSTANT_P (y) && code == REG |
| && REGNO_QTY_VALID_P (REGNO (x)) |
| && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]] |
| && rtx_equal_p (y, qty_const[reg_qty[REGNO (x)]])) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ |
| if (GET_MODE (x) != GET_MODE (y)) |
| return 0; |
| |
| switch (code) |
| { |
| case PC: |
| case CC0: |
| return x == y; |
| |
| case CONST_INT: |
| return INTVAL (x) == INTVAL (y); |
| |
| case LABEL_REF: |
| return XEXP (x, 0) == XEXP (y, 0); |
| |
| case SYMBOL_REF: |
| return XSTR (x, 0) == XSTR (y, 0); |
| |
| case REG: |
| { |
| int regno = REGNO (y); |
| int endregno |
| = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1 |
| : HARD_REGNO_NREGS (regno, GET_MODE (y))); |
| int i; |
| |
| /* If the quantities are not the same, the expressions are not |
| equivalent. If there are and we are not to validate, they |
| are equivalent. Otherwise, ensure all regs are up-to-date. */ |
| |
| if (reg_qty[REGNO (x)] != reg_qty[regno]) |
| return 0; |
| |
| if (! validate) |
| return 1; |
| |
| for (i = regno; i < endregno; i++) |
| if (reg_in_table[i] != reg_tick[i]) |
| return 0; |
| |
| return 1; |
| } |
| |
| /* For commutative operations, check both orders. */ |
| case PLUS: |
| case MULT: |
| case AND: |
| case IOR: |
| case XOR: |
| case NE: |
| case EQ: |
| return ((exp_equiv_p (XEXP (x, 0), XEXP (y, 0), validate, equal_values) |
| && exp_equiv_p (XEXP (x, 1), XEXP (y, 1), |
| validate, equal_values)) |
| || (exp_equiv_p (XEXP (x, 0), XEXP (y, 1), |
| validate, equal_values) |
| && exp_equiv_p (XEXP (x, 1), XEXP (y, 0), |
| validate, equal_values))); |
| } |
| |
| /* Compare the elements. If any pair of corresponding elements |
| fail to match, return 0 for the whole things. */ |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| { |
| switch (fmt[i]) |
| { |
| case 'e': |
| if (! exp_equiv_p (XEXP (x, i), XEXP (y, i), validate, equal_values)) |
| return 0; |
| break; |
| |
| case 'E': |
| if (XVECLEN (x, i) != XVECLEN (y, i)) |
| return 0; |
| for (j = 0; j < XVECLEN (x, i); j++) |
| if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j), |
| validate, equal_values)) |
| return 0; |
| break; |
| |
| case 's': |
| if (strcmp (XSTR (x, i), XSTR (y, i))) |
| return 0; |
| break; |
| |
| case 'i': |
| if (XINT (x, i) != XINT (y, i)) |
| return 0; |
| break; |
| |
| case 'w': |
| if (XWINT (x, i) != XWINT (y, i)) |
| return 0; |
| break; |
| |
| case '0': |
| break; |
| |
| default: |
| abort (); |
| } |
| } |
| |
| return 1; |
| } |
| |
| /* Return 1 iff any subexpression of X matches Y. |
| Here we do not require that X or Y be valid (for registers referred to) |
| for being in the hash table. */ |
| |
| static int |
| refers_to_p (x, y) |
| rtx x, y; |
| { |
| register int i; |
| register enum rtx_code code; |
| register char *fmt; |
| |
| repeat: |
| if (x == y) |
| return 1; |
| if (x == 0 || y == 0) |
| return 0; |
| |
| code = GET_CODE (x); |
| /* If X as a whole has the same code as Y, they may match. |
| If so, return 1. */ |
| if (code == GET_CODE (y)) |
| { |
| if (exp_equiv_p (x, y, 0, 1)) |
| return 1; |
| } |
| |
| /* X does not match, so try its subexpressions. */ |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| if (fmt[i] == 'e') |
| { |
| if (i == 0) |
| { |
| x = XEXP (x, 0); |
| goto repeat; |
| } |
| else |
| if (refers_to_p (XEXP (x, i), y)) |
| return 1; |
| } |
| else if (fmt[i] == 'E') |
| { |
| int j; |
| for (j = 0; j < XVECLEN (x, i); j++) |
| if (refers_to_p (XVECEXP (x, i, j), y)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* Given ADDR and SIZE (a memory address, and the size of the memory reference), |
| set PBASE, PSTART, and PEND which correspond to the base of the address, |
| the starting offset, and ending offset respectively. |
| |
| ADDR is known to be a nonvarying address. */ |
| |
| /* ??? Despite what the comments say, this function is in fact frequently |
| passed varying addresses. This does not appear to cause any problems. */ |
| |
| static void |
| set_nonvarying_address_components (addr, size, pbase, pstart, pend) |
| rtx addr; |
| int size; |
| rtx *pbase; |
| HOST_WIDE_INT *pstart, *pend; |
| { |
| rtx base; |
| HOST_WIDE_INT start, end; |
| |
| base = addr; |
| start = 0; |
| end = 0; |
| |
| /* Registers with nonvarying addresses usually have constant equivalents; |
| but the frame pointer register is also possible. */ |
| if (GET_CODE (base) == REG |
| && qty_const != 0 |
| && REGNO_QTY_VALID_P (REGNO (base)) |
| && qty_mode[reg_qty[REGNO (base)]] == GET_MODE (base) |
| && qty_const[reg_qty[REGNO (base)]] != 0) |
| base = qty_const[reg_qty[REGNO (base)]]; |
| else if (GET_CODE (base) == PLUS |
| && GET_CODE (XEXP (base, 1)) == CONST_INT |
| && GET_CODE (XEXP (base, 0)) == REG |
| && qty_const != 0 |
| && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0))) |
| && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]] |
| == GET_MODE (XEXP (base, 0))) |
| && qty_const[reg_qty[REGNO (XEXP (base, 0))]]) |
| { |
| start = INTVAL (XEXP (base, 1)); |
| base = qty_const[reg_qty[REGNO (XEXP (base, 0))]]; |
| } |
| /* This can happen as the result of virtual register instantiation, |
| if the initial offset is too large to be a valid address. */ |
| else if (GET_CODE (base) == PLUS |
| && GET_CODE (XEXP (base, 0)) == REG |
| && GET_CODE (XEXP (base, 1)) == REG |
| && qty_const != 0 |
| && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0))) |
| && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]] |
| == GET_MODE (XEXP (base, 0))) |
| && qty_const[reg_qty[REGNO (XEXP (base, 0))]] |
| && REGNO_QTY_VALID_P (REGNO (XEXP (base, 1))) |
| && (qty_mode[reg_qty[REGNO (XEXP (base, 1))]] |
| == GET_MODE (XEXP (base, 1))) |
| && qty_const[reg_qty[REGNO (XEXP (base, 1))]]) |
| { |
| rtx tem = qty_const[reg_qty[REGNO (XEXP (base, 1))]]; |
| base = qty_const[reg_qty[REGNO (XEXP (base, 0))]]; |
| |
| /* One of the two values must be a constant. */ |
| if (GET_CODE (base) != CONST_INT) |
| { |
| if (GET_CODE (tem) != CONST_INT) |
| abort (); |
| start = INTVAL (tem); |
| } |
| else |
| { |
| start = INTVAL (base); |
| base = tem; |
| } |
| } |
| |
| /* Handle everything that we can find inside an address that has been |
| viewed as constant. */ |
| |
| while (1) |
| { |
| /* If no part of this switch does a "continue", the code outside |
| will exit this loop. */ |
| |
| switch (GET_CODE (base)) |
| { |
| case LO_SUM: |
| /* By definition, operand1 of a LO_SUM is the associated constant |
| address. Use the associated constant address as the base |
| instead. */ |
| base = XEXP (base, 1); |
| continue; |
| |
| case CONST: |
| /* Strip off CONST. */ |
| base = XEXP (base, 0); |
| continue; |
| |
| case PLUS: |
| if (GET_CODE (XEXP (base, 1)) == CONST_INT) |
| { |
| start += INTVAL (XEXP (base, 1)); |
| base = XEXP (base, 0); |
| continue; |
| } |
| break; |
| |
| case AND: |
| /* Handle the case of an AND which is the negative of a power of |
| two. This is used to represent unaligned memory operations. */ |
| if (GET_CODE (XEXP (base, 1)) == CONST_INT |
| && exact_log2 (- INTVAL (XEXP (base, 1))) > 0) |
| { |
| set_nonvarying_address_components (XEXP (base, 0), size, |
| pbase, pstart, pend); |
| |
| /* Assume the worst misalignment. START is affected, but not |
| END, so compensate but adjusting SIZE. Don't lose any |
| constant we already had. */ |
| |
| size = *pend - *pstart - INTVAL (XEXP (base, 1)) - 1; |
| start += *pstart + INTVAL (XEXP (base, 1)) + 1; |
| end += *pend; |
| base = *pbase; |
| } |
| break; |
| } |
| |
| break; |
| } |
| |
| if (GET_CODE (base) == CONST_INT) |
| { |
| start += INTVAL (base); |
| base = const0_rtx; |
| } |
| |
| end = start + size; |
| |
| /* Set the return values. */ |
| *pbase = base; |
| *pstart = start; |
| *pend = end; |
| } |
| |
| /* Return 1 iff any subexpression of X refers to memory |
| at an address of BASE plus some offset |
| such that any of the bytes' offsets fall between START (inclusive) |
| and END (exclusive). |
| |
| The value is undefined if X is a varying address (as determined by |
| cse_rtx_addr_varies_p). This function is not used in such cases. |
| |
| When used in the cse pass, `qty_const' is nonzero, and it is used |
| to treat an address that is a register with a known constant value |
| as if it were that constant value. |
| In the loop pass, `qty_const' is zero, so this is not done. */ |
| |
| static int |
| refers_to_mem_p (x, base, start, end) |
| rtx x, base; |
| HOST_WIDE_INT start, end; |
| { |
| register HOST_WIDE_INT i; |
| register enum rtx_code code; |
| register char *fmt; |
| |
| repeat: |
| if (x == 0) |
| return 0; |
| |
| code = GET_CODE (x); |
| if (code == MEM) |
| { |
| register rtx addr = XEXP (x, 0); /* Get the address. */ |
| rtx mybase; |
| HOST_WIDE_INT mystart, myend; |
| |
| set_nonvarying_address_components (addr, GET_MODE_SIZE (GET_MODE (x)), |
| &mybase, &mystart, &myend); |
| |
| |
| /* refers_to_mem_p is never called with varying addresses. |
| If the base addresses are not equal, there is no chance |
| of the memory addresses conflicting. */ |
| if (! rtx_equal_p (mybase, base)) |
| return 0; |
| |
| return myend > start && mystart < end; |
| } |
| |
| /* X does not match, so try its subexpressions. */ |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| if (fmt[i] == 'e') |
| { |
| if (i == 0) |
| { |
| x = XEXP (x, 0); |
| goto repeat; |
| } |
| else |
| if (refers_to_mem_p (XEXP (x, i), base, start, end)) |
| return 1; |
| } |
| else if (fmt[i] == 'E') |
| { |
| int j; |
| for (j = 0; j < XVECLEN (x, i); j++) |
| if (refers_to_mem_p (XVECEXP (x, i, j), base, start, end)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* Nonzero if X refers to memory at a varying address; |
| except that a register which has at the moment a known constant value |
| isn't considered variable. */ |
| |
| static int |
| cse_rtx_addr_varies_p (x) |
| rtx x; |
| { |
| /* We need not check for X and the equivalence class being of the same |
| mode because if X is equivalent to a constant in some mode, it |
| doesn't vary in any mode. */ |
| |
| if (GET_CODE (x) == MEM |
| && GET_CODE (XEXP (x, 0)) == REG |
| && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))) |
| && GET_MODE (XEXP (x, 0)) == qty_mode[reg_qty[REGNO (XEXP (x, 0))]] |
| && qty_const[reg_qty[REGNO (XEXP (x, 0))]] != 0) |
| return 0; |
| |
| if (GET_CODE (x) == MEM |
| && GET_CODE (XEXP (x, 0)) == PLUS |
| && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT |
| && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG |
| && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0))) |
| && (GET_MODE (XEXP (XEXP (x, 0), 0)) |
| == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]]) |
| && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]]) |
| return 0; |
| |
| /* This can happen as the result of virtual register instantiation, if |
| the initial constant is too large to be a valid address. This gives |
| us a three instruction sequence, load large offset into a register, |
| load fp minus a constant into a register, then a MEM which is the |
| sum of the two `constant' registers. */ |
| if (GET_CODE (x) == MEM |
| && GET_CODE (XEXP (x, 0)) == PLUS |
| && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG |
| && GET_CODE (XEXP (XEXP (x, 0), 1)) == REG |
| && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0))) |
| && (GET_MODE (XEXP (XEXP (x, 0), 0)) |
| == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]]) |
| && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]] |
| && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 1))) |
| && (GET_MODE (XEXP (XEXP (x, 0), 1)) |
| == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]]) |
| && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]]) |
| return 0; |
| |
| return rtx_addr_varies_p (x); |
| } |
| |
| /* Canonicalize an expression: |
| replace each register reference inside it |
| with the "oldest" equivalent register. |
| |
| If INSN is non-zero and we are replacing a pseudo with a hard register |
| or vice versa, validate_change is used to ensure that INSN remains valid |
| after we make our substitution. The calls are made with IN_GROUP non-zero |
| so apply_change_group must be called upon the outermost return from this |
| function (unless INSN is zero). The result of apply_change_group can |
| generally be discarded since the changes we are making are optional. */ |
| |
| static rtx |
| canon_reg (x, insn) |
| rtx x; |
| rtx insn; |
| { |
| register int i; |
| register enum rtx_code code; |
| register char *fmt; |
| |
| if (x == 0) |
| return x; |
| |
| code = GET_CODE (x); |
| switch (code) |
| { |
| case PC: |
| case CC0: |
| case CONST: |
| case CONST_INT: |
| case CONST_DOUBLE: |
| case SYMBOL_REF: |
| case LABEL_REF: |
| case ADDR_VEC: |
| case ADDR_DIFF_VEC: |
| return x; |
| |
| case REG: |
| { |
| register int first; |
| |
| /* Never replace a hard reg, because hard regs can appear |
| in more than one machine mode, and we must preserve the mode |
| of each occurrence. Also, some hard regs appear in |
| MEMs that are shared and mustn't be altered. Don't try to |
| replace any reg that maps to a reg of class NO_REGS. */ |
| if (REGNO (x) < FIRST_PSEUDO_REGISTER |
| || ! REGNO_QTY_VALID_P (REGNO (x))) |
| return x; |
| |
| first = qty_first_reg[reg_qty[REGNO (x)]]; |
| return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first] |
| : REGNO_REG_CLASS (first) == NO_REGS ? x |
| : gen_rtx (REG, qty_mode[reg_qty[REGNO (x)]], first)); |
| } |
| } |
| |
| fmt = GET_RTX_FORMAT (code); |
| for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| { |
| register int j; |
| |
| if (fmt[i] == 'e') |
| { |
| rtx new = canon_reg (XEXP (x, i), insn); |
| int insn_code; |
| |
| /* If replacing pseudo with hard reg or vice versa, ensure the |
| insn remains valid. Likewise if the insn has MATCH_DUPs. */ |
| if (insn != 0 && new != 0 |
| && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG |
| && (((REGNO (new) < FIRST_PSEUDO_REGISTER) |
| != (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER)) |
| || (insn_code = recog_memoized (insn)) < 0 |
| || insn_n_dups[insn_code] > 0)) |
| validate_change (insn, &XEXP (x, i), new, 1); |
| else |
| XEXP (x, i) = new; |
| } |
| else if (fmt[i] == 'E') |
| for (j = 0; j < XVECLEN (x, i); j++) |
| XVECEXP (x, i, j) = canon_reg (XVECEXP (x, i, j), insn); |
| } |
| |
| return x; |
| } |
| |
| /* LOC is a location within INSN that is an operand address (the contents of |
| a MEM). Find the best equivalent address to use that is valid for this |
| insn. |
| |
| On most CISC machines, complicated address modes are costly, and rtx_cost |
| is a good approximation for that cost. However, most RISC machines have |
| only a few (usually only one) memory reference formats. If an address is |
| valid at all, it is often just as cheap as any other address. Hence, for |
| RISC machines, we use the configuration macro `ADDRESS_COST' to compare the |
| costs of various addresses. For two addresses of equal cost, choose the one |
| with the highest `rtx_cost' value as that has the potential of eliminating |
| the most insns. For equal costs, we choose the first in the equivalence |
| class. Note that we ignore the fact that pseudo registers are cheaper |
| than hard registers here because we would also prefer the pseudo registers. |
| */ |
| |
| static void |
| find_best_addr (insn, loc) |
| rtx insn; |
| rtx *loc; |
| { |
| struct table_elt *elt, *p; |
| rtx addr = *loc; |
| int our_cost; |
| int found_better = 1; |
| int save_do_not_record = do_not_record; |
| int save_hash_arg_in_memory = hash_arg_in_memory; |
| int save_hash_arg_in_struct = hash_arg_in_struct; |
| int addr_volatile; |
| int regno; |
| unsigned hash; |
| |
| /* Do not try to replace constant addresses or addresses of local and |
| argument slots. These MEM expressions are made only once and inserted |
| in many instructions, as well as being used to control symbol table |
| output. It is not safe to clobber them. |
| |
| There are some uncommon cases where the address is already in a register |
| for some reason, but we cannot take advantage of that because we have |
| no easy way to unshare the MEM. In addition, looking up all stack |
| addresses is costly. */ |
| if ((GET_CODE (addr) == PLUS |
| && GET_CODE (XEXP (addr, 0)) == REG |
| && GET_CODE (XEXP (addr, 1)) == CONST_INT |
| && (regno = REGNO (XEXP (addr, 0)), |
| regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM |
| || regno == ARG_POINTER_REGNUM)) |
| || (GET_CODE (addr) == REG |
| && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM |
| || regno == HARD_FRAME_POINTER_REGNUM |
| || regno == ARG_POINTER_REGNUM)) |
| || CONSTANT_ADDRESS_P (addr)) |
| return; |
| |
| /* If this address is not simply a register, try to fold it. This will |
| sometimes simplify the expression. Many simplifications |
| will not be valid, but some, usually applying the associative rule, will |
| be valid and produce better code. */ |
| if (GET_CODE (addr) != REG) |
| { |
| rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX); |
| |
| if (1 |
| #ifdef ADDRESS_COST |
| && (ADDRESS_COST (folded) < ADDRESS_COST (addr) |
| || (ADDRESS_COST (folded) == ADDRESS_COST (addr) |
| && rtx_cost (folded, MEM) > rtx_cost (addr, MEM))) |
| #else |
| && rtx_cost (folded, MEM) < rtx_cost (addr, MEM) |
| #endif |
| && validate_change (insn, loc, folded, 0)) |
| addr = folded; |
| } |
| |
| /* If this address is not in the hash table, we can't look for equivalences |
| of the whole address. Also, ignore if volatile. */ |
| |
| do_not_record = 0; |
| hash = HASH (addr, Pmode); |
| addr_volatile = do_not_record; |
| do_not_record = save_do_not_record; |
| hash_arg_in_memory = save_hash_arg_in_memory; |
| hash_arg_in_struct = save_hash_arg_in_struct; |
| |
| if (addr_volatile) |
| return; |
| |
| elt = lookup (addr, hash, Pmode); |
| |
| #ifndef ADDRESS_COST |
| if (elt) |
| { |
| our_cost = elt->cost; |
| |
| /* Find the lowest cost below ours that works. */ |
| for (elt = elt->first_same_value; elt; elt = elt->next_same_value) |
| if (elt->cost < our_cost |
| && (GET_CODE (elt->exp) == REG |
| || exp_equiv_p (elt->exp, elt->exp, 1, 0)) |
| && validate_change (insn, loc, |
| canon_reg (copy_rtx (elt->exp), NULL_RTX), 0)) |
| return; |
| } |
| #else |
| |
| if (elt) |
| { |
| /* We need to find the best (under the criteria documented above) entry |
| in the class that is valid. We use the `flag' field to indicate |
| choices that were invalid and iterate until we can't find a better |
| one that hasn't already been tried. */ |
| |
| for (p = elt->first_same_value; p; p = p->next_same_value) |
| p->flag = 0; |
| |
| while (found_better) |
| { |
| int best_addr_cost = ADDRESS_COST (*loc); |
| int best_rtx_cost = (elt->cost + 1) >> 1; |
| struct table_elt *best_elt = elt; |
| |
| found_better = 0; |
| for (p = elt->first_same_value; p; p = p->next_same_value) |
| if (! p->flag |
| && (GET_CODE (p->exp) == REG |
| || exp_equiv_p (p->exp, p->exp, 1, 0)) |
| && (ADDRESS_COST (p->exp) < best_addr_cost |
| || (ADDRESS_COST (p->exp) == best_addr_cost |
| && (p->cost + 1) >> 1 > best_rtx_cost))) |
| { |
| found_better = 1; |
| best_addr_cost = ADDRESS_COST (p->exp); |
| best_rtx_cost = (p->cost + 1) >> 1; |
| best_elt = p; |
| } |
| |
| if (found_better) |
| { |
| if (validate_change (insn, loc, |
| canon_reg (copy_rtx (best_elt->exp), |
| NULL_RTX), 0)) |
| return; |
| else |
| best_elt->flag = 1; |
| } |
| } |
| } |
| |
| /* If the address is a binary operation with the first operand a register |
| and the second a constant, do the same as above, but looking for |
| equivalences of the register. Then try to simplify before checking for |
| the best address to use. This catches a few cases: First is when we |
| have REG+const and the register is another REG+const. We can often merge |
| the constants and eliminate one insn and one register. It may also be |
| that a machine has a cheap REG+REG+const. Finally, this improves the |
| code on the Alpha for unaligned byte stores. */ |
| |
| if (flag_expensive_optimizations |
| && (GET_RTX_CLASS (GET_CODE (*loc)) == '2' |
| || GET_RTX_CLASS (GET_CODE (*loc)) == 'c') |
| && GET_CODE (XEXP (*loc, 0)) == REG |
| && GET_CODE (XEXP (*loc, 1)) == CONST_INT) |
| { |
| rtx c = XEXP (*loc, 1); |
| |
| do_not_record = 0; |
| hash = HASH (XEXP (*loc, 0), Pmode); |
| do_not_record = save_do_not_record; |
| hash_arg_in_memory = save_hash_arg_in_memory; |
| hash_arg_in_struct = save_hash_arg_in_struct; |
| |
| elt = lookup (XEXP (*loc, 0), hash, Pmode); |
| if (elt == 0) |
| return; |
| |
| /* We need to find the best (under the criteria documented above) entry |
| in the class that is valid. We use the `flag' field to indicate |
| choices that were invalid and iterate until we can't find a better |
| one that hasn't already been tried. */ |
| |
| for (p = elt->first_same_value; p; p = p->next_same_value) |
| p->flag = 0; |
| |
| while (found_better) |
| { |
| int best_addr_cost = ADDRESS_COST (*loc); |
| int best_rtx_cost = (COST (*loc) + 1) >> 1; |
| struct table_elt *best_elt = elt; |
| rtx best_rtx = *loc; |
| int count; |
| |
| /* This is at worst case an O(n^2) algorithm, so limit our search |
| to the first 32 elements on the list. This avoids trouble |
| compiling code with very long basic blocks that can easily |
| call cse_gen_binary so many times that we run out of memory. */ |
| |
| found_better = 0; |
| for (p = elt->first_same_value, count = 0; |
| p && count < 32; |
| p = p->next_same_value, count++) |
| if (! p->flag |
| && (GET_CODE (p->exp) == REG |
| || exp_equiv_p (p->exp, p->exp, 1, 0))) |
| { |
| rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c); |
| |
| if ((ADDRESS_COST (new) < best_addr_cost |
| || (ADDRESS_COST (new) == best_addr_cost |
| && (COST (new) + 1) >> 1 > best_rtx_cost))) |
| { |
| found_better = 1; |
| best_addr_cost = ADDRESS_COST (new); |
| best_rtx_cost = (COST (new) + 1) >> 1; |
| best_elt = p; |
| best_rtx = new; |
| } |
| } |
| |
| if (found_better) |
| { |
| if (validate_change (insn, loc, |
| canon_reg (copy_rtx (best_rtx), |
| NULL_RTX), 0)) |
| return; |
| else |
| best_elt->flag = 1; |
| } |
| } |
| } |
| #endif |
| } |
| |
| /* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison |
| operation (EQ, NE, GT, etc.), follow it back through the hash table and |
| what values are being compared. |
| |
| *PARG1 and *PARG2 are updated to contain the rtx representing the values |
| actually being compared. For example, if *PARG1 was (cc0) and *PARG2 |
| was (const_int 0), *PARG1 and *PARG2 will be set to the objects that were |
| compared to produce cc0. |
| |
| The return value is the comparison operator and is either the code of |
| A or the code corresponding to the inverse of the comparison. */ |
| |
| static enum rtx_code |
| find_comparison_args (code, parg1, parg2, pmode1, pmode2) |
| enum rtx_code code; |
| rtx *parg1, *parg2; |
| enum machine_mode *pmode1, *pmode2; |
| { |
| rtx arg1, arg2; |
| |
| arg1 = *parg1, arg2 = *parg2; |
| |
| /* If ARG2 is const0_rtx, see what ARG1 is equivalent to. */ |
| |
| while (arg2 == CONST0_RTX (GET_MODE (arg1))) |
| { |
| /* Set non-zero when we find something of interest. */ |
| rtx x = 0; |
| int reverse_code = 0; |
| struct table_elt *p = 0; |
| |
| /* If arg1 is a COMPARE, extract the comparison arguments from it. |
| On machines with CC0, this is the only case that can occur, since |
| fold_rtx will return the COMPARE or item being compared with zero |
| when given CC0. */ |
| |
| if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx) |
| x = arg1; |
| |
| /* If ARG1 is a comparison operator and CODE is testing for |
| STORE_FLAG_VALUE, get the inner arguments. */ |
| |
| else if (GET_RTX_CLASS (GET_CODE (arg1)) == '<') |
| { |
| if (code == NE |
| || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT |
| && code == LT && STORE_FLAG_VALUE == -1) |
| #ifdef FLOAT_STORE_FLAG_VALUE |
| || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT |
| && FLOAT_STORE_FLAG_VALUE < 0) |
| #endif |
| ) |
| x = arg1; |
| else if (code == EQ |
| || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT |
| && code == GE && STORE_FLAG_VALUE == -1) |
| #ifdef FLOAT_STORE_FLAG_VALUE |
| || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT |
| && FLOAT_STORE_FLAG_VALUE < 0) |
| #endif |
| ) |
| x = arg1, reverse_code = 1; |
| } |
| |
| /* ??? We could also check for |
| |
| (ne (and (eq (...) (const_int 1))) (const_int 0)) |
| |
| and related forms, but let's wait until we see them occurring. */ |
| |
| if (x == 0) |
| /* Look up ARG1 in the hash table and see if it has an equivalence |
| that lets us see what is being compared. */ |
| p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) % NBUCKETS, |
| GET_MODE (arg1)); |
| if (p) p = p->first_same_value; |
| |
| for (; p; p = p->next_same_value) |
| { |
| enum machine_mode inner_mode = GET_MODE (p->exp); |
| |
| /* If the entry isn't valid, skip it. */ |
| if (! exp_equiv_p (p->exp, p->exp, 1, 0)) |
| continue; |
| |
| if (GET_CODE (p->exp) == COMPARE |
| /* Another possibility is that this machine has a compare insn |
| that includes the comparison code. In that case, ARG1 would |
| be equivalent to a comparison operation that would set ARG1 to |
| either STORE_FLAG_VALUE or zero. If this is an NE operation, |
| ORIG_CODE is the actual comparison being done; if it is an EQ, |
| we must reverse ORIG_CODE. On machine with a negative value |
| for STORE_FLAG_VALUE, also look at LT and GE operations. */ |
| || ((code == NE |
| || (code == LT |
| && GET_MODE_CLASS (inner_mode) == MODE_INT |
| && (GET_MODE_BITSIZE (inner_mode) |
| <= HOST_BITS_PER_WIDE_INT) |
| && (STORE_FLAG_VALUE |
| & ((HOST_WIDE_INT) 1 |
| << (GET_MODE_BITSIZE (inner_mode) - 1)))) |
| #ifdef FLOAT_STORE_FLAG_VALUE |
| || (code == LT |
| && GET_MODE_CLASS (inner_mode) == MODE_FLOAT |
| && FLOAT_STORE_FLAG_VALUE < 0) |
| #endif |
| ) |
| && GET_RTX_CLASS (GET_CODE (p->exp)) == '<')) |
| { |
| x = p->exp; |
| break; |
| } |
| else if ((code == EQ |
| || (code == GE |
| && GET_MODE_CLASS (inner_mode) == MODE_INT |
| && (GET_MODE_BITSIZE (inner_mode) |
| <= HOST_BITS_PER_WIDE_INT) |
| && (STORE_FLAG_VALUE |
| & ((HOST_WIDE_INT) 1 |
| << (GET_MODE_BITSIZE (inner_mode) - 1)))) |
| #ifdef FLOAT_STORE_FLAG_VALUE |
| || (code == GE |
| && GET_MODE_CLASS (inner_mode) == MODE_FLOAT |
| && FLOAT_STORE_FLAG_VALUE < 0) |
| #endif |
| ) |
| && GET_RTX_CLASS (GET_CODE (p->exp)) == '<') |
| { |
| reverse_code = 1; |
| x = p->exp; |
| break; |
| } |
| |
| /* If this is fp + constant, the equivalent is a better operand since |
| it may let us predict the value of the comparison. */ |
| else if (NONZERO_BASE_PLUS_P (p->exp)) |
| { |
| arg1 = p->exp; |
| continue; |
| } |
| } |
| |
| /* If we didn't find a useful equivalence for ARG1, we are done. |
| Otherwise, set up for the next iteration. */ |
| if (x == 0) |
| break; |
| |
| arg1 = XEXP (x, 0), arg2 = XEXP (x, 1); |
| if (GET_RTX_CLASS (GET_CODE (x)) == '<') |
| code = GET_CODE (x); |
| |
| if (reverse_code) |
| code = reverse_condition (code); |
| } |
| |
| /* Return our results. Return the modes from before fold_rtx |
| because fold_rtx might produce const_int, and then it's too late. */ |
| *pmode1 = GET_MODE (arg1), *pmode2 = GET_MODE (arg2); |
| *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0); |
| |
| return code; |
| } |
| |
| /* Try to simplify a unary operation CODE whose output mode is to be |
| MODE with input operand OP whose mode was originally OP_MODE. |
| Return zero if no simplification can be made. */ |
| |
| rtx |
| simplify_unary_operation (code, mode, op, op_mode) |
| enum rtx_code code; |
| enum machine_mode mode; |
| rtx op; |
| enum machine_mode op_mode; |
| { |
| register int width = GET_MODE_BITSIZE (mode); |
| |
| /* The order of these tests is critical so that, for example, we don't |
| check the wrong mode (input vs. output) for a conversion operation, |
| such as FIX. At some point, this should be simplified. */ |
| |
| #if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC) |
| |
| if (code == FLOAT && GET_MODE (op) == VOIDmode |
| && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)) |
| { |
| HOST_WIDE_INT hv, lv; |
| REAL_VALUE_TYPE d; |
| |
| if (GET_CODE (op) == CONST_INT) |
| lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0; |
| else |
| lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op); |
| |
| #ifdef REAL_ARITHMETIC |
| REAL_VALUE_FROM_INT (d, lv, hv, mode); |
| #else |
| if (hv < 0) |
| { |
| d = (double) (~ hv); |
| d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) |
| * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))); |
| d += (double) (unsigned HOST_WIDE_INT) (~ lv); |
| d = (- d - 1.0); |
| } |
| else |
| { |
| d = (double) hv; |
| d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) |
| * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))); |
| d += (double) (unsigned HOST_WIDE_INT) lv; |
| } |
| #endif /* REAL_ARITHMETIC */ |
| d = real_value_truncate (mode, d); |
| return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); |
| } |
| else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode |
| && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)) |
| { |
| HOST_WIDE_INT hv, lv; |
| REAL_VALUE_TYPE d; |
| |
| if (GET_CODE (op) == CONST_INT) |
| lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0; |
| else |
| lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op); |
| |
| if (op_mode == VOIDmode) |
| { |
| /* We don't know how to interpret negative-looking numbers in |
| this case, so don't try to fold those. */ |
| if (hv < 0) |
| return 0; |
| } |
| else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2) |
| ; |
| else |
| hv = 0, lv &= GET_MODE_MASK (op_mode); |
| |
| #ifdef REAL_ARITHMETIC |
| REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode); |
| #else |
| |
| d = (double) (unsigned HOST_WIDE_INT) hv; |
| d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) |
| * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))); |
| d += (double) (unsigned HOST_WIDE_INT) lv; |
| #endif /* REAL_ARITHMETIC */ |
| d = real_value_truncate (mode, d); |
| return CONST_DOUBLE_FROM_REAL_VALUE (d, mode); |
| } |
| #endif |
| |
| if (GET_CODE (op) == CONST_INT |
| && width <= HOST_BITS_PER_WIDE_INT && width > 0) |
| { |
| register HOST_WIDE_INT arg0 = INTVAL (op); |
| register HOST_WIDE_INT val; |
| |
| switch (code) |
| |