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

📄 cse.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Common subexpression elimination for GNU compiler.   Copyright (C) 1987, 88, 89, 92-7, 1998 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 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 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, 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 "expr.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;/* One plus largest instruction UID used in this function at time of   cse_main call.  */static int max_insn_uid;/* 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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -