📄 cse.c
字号:
/* Common subexpression elimination for GNU compiler. Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "config.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "flags.h"#include "real.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. 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.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. Regs are preferred to constants as they are to everything else, but 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) (pseudo) register in the chain of registers that currently contain this quantity. */static int *qty_first_reg;static int *qty_last_reg;/* 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;/* Value stored in CC0 by previous insn: 0 if previous insn didn't store in CC0. else 0100 + (M&7)<<3 + (N&7) where M is 1, 0 or -1 if result was >, == or < as signed number and N is 1, 0 or -1 if result was >, == or < as unsigned number. 0200 bit may also be set, meaning that only == and != comparisons have known results. */static int prev_insn_cc0;/* For machines where CC0 is one bit, we may see CC0 assigned a constant value (after fold_rtx). Record here the value stored in the previous insn (0 if none). */static rtx prev_insn_explicit_cc0;/* Previous actual insn. 0 if at first insn of basic block. */static rtx prev_insn;/* Insn being scanned. */static rtx this_insn;/* Index by (pseudo) register number, gives the quantity number of the register's current contents. */static int *reg_qty;/* Index by (pseudo) register number, gives the number of the next (pseudo) register in the chain of registers sharing the same value. Or -1 if this register is at the end of the chain. */static int *reg_next_eqv;/* Index by (pseudo) register number, gives the number of the previous (pseudo) register in the chain of registers sharing the same value. Or -1 if this register is at the beginning of the chain. */static int *reg_prev_eqv;/* Index by (pseudo) register number, gives the latest rtx to use to insert a ref to that register. */static rtx *reg_rtx;/* Index by (pseudo) register number, gives the number of times that register has been altered in the current basic block. */static int *reg_tick;/* Index by (pseudo) 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;/* Two vectors of max_reg ints: one containing all -1's; in the other, element i contains i. These are used to initialize various other vectors fast. */static int *all_minus_one;static int *consec_ints;/* Set nonzero in cse_insn to tell cse_basic_block to skip immediately to the next basic block and treat it as a continuation of this one. */static int cse_skip_to_next_block;/* 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 monononically always. We use them to see whether a reg is used outside a given basic block. */static short *uid_cuid;/* 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;/* canon_hash stores 1 in do_not_record if it notices a reference to CC0, CC1 or PC. */static int do_not_record;/* 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 `equivalence_only' field means that this expression came from a REG_EQUIV or REG_EQUAL note; it is not valid for substitution into an insn. 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 `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 equivalence_only;};#define HASH(x, m) (canon_hash (x, m) % NBUCKETS)/* 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 31static 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;/* 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. 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 var : 1; /* Invalidate variable addresses. */ int nonscalar : 1; /* Invalidate all but scalar variables. */ int all : 1; /* Invalidate all memory refs. */};/* Nonzero if X has the form (PLUS frame-pointer integer). */#define FIXED_BASE_PLUS_P(X) \ (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ && (XEXP (X, 0) == frame_pointer_rtx || XEXP (X, 0) == arg_pointer_rtx))static struct table_elt *lookup ();static void free_element ();static void remove_invalid_refs ();static int exp_equiv_p ();int refers_to_p ();int refers_to_mem_p ();static void invalidate_from_clobbers ();static int safe_hash ();static int canon_hash ();static rtx equiv_constant ();static int get_integer_term ();static rtx get_related_value ();static void note_mem_written ();static int cse_rtx_addr_varies_p ();static int fold_cc0 ();/* Return an estimate of the cost of computing rtx X. The only use of this is to compare the costs of two expressions to decide whether to replace one with the other. */static intrtx_cost (x) rtx x;{ register int i, j; register enum rtx_code code; register char *fmt; register int total; if (x == 0) return 0; code = GET_CODE (x); switch (code) { case REG: return 1; case SUBREG: return 2; CONST_COSTS (x, code); } total = 2; if (code == MEM) total = 2 * GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD; /* Sum the costs of the sub-rtx's, plus 2 just put in. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -