⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cse.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -