GCC Middle and Back End API Reference
cse.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "target.h"
#include "rtl.h"
#include "tree.h"
#include "cfghooks.h"
#include "df.h"
#include "memmodel.h"
#include "tm_p.h"
#include "insn-config.h"
#include "regs.h"
#include "emit-rtl.h"
#include "recog.h"
#include "cfgrtl.h"
#include "cfganal.h"
#include "cfgcleanup.h"
#include "alias.h"
#include "toplev.h"
#include "rtlhooks-def.h"
#include "tree-pass.h"
#include "dbgcnt.h"
#include "rtl-iter.h"
#include "function-abi.h"
#include "rtlanal.h"
#include "expr.h"
Include dependency graph for cse.cc:

Data Structures

struct  qty_table_elem
 
struct  reg_eqv_elem
 
struct  cse_reg_info
 
struct  table_elt
 
struct  branch_path
 
struct  cse_basic_block_data
 
struct  set
 

Macros

#define HASH_SHIFT   5
 
#define HASH_SIZE   (1 << HASH_SHIFT)
 
#define HASH_MASK   (HASH_SIZE - 1)
 
#define FIXED_REGNO_P(N)
 
#define CHEAP_REGNO(N)
 
#define COST(X, MODE)    (REG_P (X) ? 0 : notreg_cost (X, MODE, SET, 1))
 
#define COST_IN(X, MODE, OUTER, OPNO)    (REG_P (X) ? 0 : notreg_cost (X, MODE, OUTER, OPNO))
 
#define REG_TICK(N)   (get_cse_reg_info (N)->reg_tick)
 
#define REG_IN_TABLE(N)   (get_cse_reg_info (N)->reg_in_table)
 
#define SUBREG_TICKED(N)   (get_cse_reg_info (N)->subreg_ticked)
 
#define REG_QTY(N)   (get_cse_reg_info (N)->reg_qty)
 
#define REGNO_QTY_VALID_P(N)   (REG_QTY (N) >= 0)
 
#define CHEAPER(X, Y)    (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
 
#define RTL_HOOKS_GEN_LOWPART   gen_lowpart_if_possible
 

Functions

static bool fixed_base_plus_p (rtx x)
 
static int notreg_cost (rtx, machine_mode, enum rtx_code, int)
 
static int preferable (int, int, int, int)
 
static void new_basic_block (void)
 
static void make_new_qty (unsigned int, machine_mode)
 
static void make_regs_eqv (unsigned int, unsigned int)
 
static void delete_reg_equiv (unsigned int)
 
static bool mention_regs (rtx)
 
static bool insert_regs (rtx, struct table_elt *, bool)
 
static void remove_from_table (struct table_elt *, unsigned)
 
static void remove_pseudo_from_table (rtx, unsigned)
 
static struct table_eltlookup (rtx, unsigned, machine_mode)
 
static struct table_eltlookup_for_remove (rtx, unsigned, machine_mode)
 
static rtx lookup_as_function (rtx, enum rtx_code)
 
static struct table_eltinsert_with_costs (rtx, struct table_elt *, unsigned, machine_mode, int, int)
 
static struct table_eltinsert (rtx, struct table_elt *, unsigned, machine_mode)
 
static void merge_equiv_classes (struct table_elt *, struct table_elt *)
 
static void invalidate (rtx, machine_mode)
 
static void remove_invalid_refs (unsigned int)
 
static void remove_invalid_subreg_refs (unsigned int, poly_uint64, machine_mode)
 
static void rehash_using_reg (rtx)
 
static void invalidate_memory (void)
 
static rtx use_related_value (rtx, struct table_elt *)
 
static unsigned canon_hash (rtx, machine_mode)
 
static unsigned safe_hash (rtx, machine_mode)
 
static unsigned hash_rtx_string (const char *)
 
static rtx canon_reg (rtx, rtx_insn *)
 
static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *, machine_mode *, machine_mode *)
 
static rtx fold_rtx (rtx, rtx_insn *)
 
static rtx equiv_constant (rtx)
 
static void record_jump_equiv (rtx_insn *, bool)
 
static void record_jump_cond (enum rtx_code, machine_mode, rtx, rtx)
 
static void cse_insn (rtx_insn *)
 
static void cse_prescan_path (struct cse_basic_block_data *)
 
static void invalidate_from_clobbers (rtx_insn *)
 
static void invalidate_from_sets_and_clobbers (rtx_insn *)
 
static void cse_extended_basic_block (struct cse_basic_block_data *)
 
void dump_class (struct table_elt *)
 
static void get_cse_reg_info_1 (unsigned int regno)
 
static struct cse_reg_infoget_cse_reg_info (unsigned int regno)
 
static void flush_hash_table (void)
 
static bool insn_live_p (rtx_insn *, int *)
 
static bool set_live_p (rtx, int *)
 
static void cse_change_cc_mode_insn (rtx_insn *, rtx)
 
static void cse_change_cc_mode_insns (rtx_insn *, rtx_insn *, rtx)
 
static machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx, bool)
 
static unsigned HASH (rtx x, machine_mode mode)
 
static unsigned SAFE_HASH (rtx x, machine_mode mode)
 
static int approx_reg_cost (const_rtx x)
 
static void init_cse_reg_info (unsigned int nregs)
 
static bool compute_const_anchors (rtx cst, HOST_WIDE_INT *lower_base, HOST_WIDE_INT *lower_offs, HOST_WIDE_INT *upper_base, HOST_WIDE_INT *upper_offs)
 
static void insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs, machine_mode mode)
 
static void insert_const_anchors (rtx reg, rtx cst, machine_mode mode)
 
static rtx find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT offs, unsigned *old)
 
static rtx try_const_anchors (rtx src_const, machine_mode mode)
 
static void remove_from_table (struct table_elt *elt, unsigned int hash)
 
static void remove_pseudo_from_table (rtx x, unsigned int hash)
 
static struct table_eltlookup (rtx x, unsigned int hash, machine_mode mode)
 
static struct table_eltlookup_for_remove (rtx x, unsigned int hash, machine_mode mode)
 
static struct table_eltinsert_with_costs (rtx x, struct table_elt *classp, unsigned int hash, machine_mode mode, int cost, int reg_cost)
 
static struct table_eltinsert (rtx x, struct table_elt *classp, unsigned int hash, machine_mode mode)
 
static bool check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
 
static void invalidate_reg (rtx x)
 
static void invalidate_dest (rtx dest)
 
static void invalidate_for_call (rtx_insn *insn)
 
unsigned hash_rtx (const_rtx x, machine_mode mode, int *do_not_record_p, int *hash_arg_in_memory_p, bool have_reg_qty, hash_rtx_callback_function cb)
 
bool exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
 
static void validate_canon_reg (rtx *xloc, rtx_insn *insn)
 
static rtx record_jump_cond_subreg (machine_mode mode, rtx op)
 
static void try_back_substitute_reg (rtx set, rtx_insn *insn)
 
static void add_to_set (vec< struct set > *sets, rtx x, bool is_fake_set)
 
static int find_sets_in_insn (rtx_insn *insn, vec< struct set > *psets)
 
static void canon_asm_operands (rtx x, rtx_insn *insn)
 
static void canonicalize_insn (rtx_insn *insn, vec< struct set > *psets)
 
static rtx cse_process_note (rtx)
 
static rtx cse_process_note_1 (rtx x, const_rtx, void *)
 
static bool cse_find_path (basic_block first_bb, struct cse_basic_block_data *data, int follow_jumps)
 
static void cse_dump_path (struct cse_basic_block_data *data, int nsets, FILE *f)
 
static bool have_eh_succ_edges (basic_block bb)
 
static bool check_for_label_ref (rtx_insn *insn)
 
static int cse_main (rtx_insn *f, int nregs)
 
static void count_reg_usage (rtx x, int *counts, rtx dest, int incr)
 
static bool is_dead_reg (const_rtx x, int *counts)
 
static void count_stores (rtx x, const_rtx set, void *data)
 
static bool is_dead_debug_insn (const_rtx pat, int *counts, rtx *replacements, bool *seen_repl)
 
static rtx replace_dead_reg (rtx x, const_rtx old_rtx, void *data)
 
int delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
static void cse_change_cc_mode (subrtx_ptr_iterator::array_type &array, rtx *loc, rtx_insn *insn, rtx newreg)
 
static void cse_condition_code_reg (void)
 
static unsigned int rest_of_handle_cse (void)
 
rtl_opt_passmake_pass_cse (gcc::context *ctxt)
 
static unsigned int rest_of_handle_cse2 (void)
 
rtl_opt_passmake_pass_cse2 (gcc::context *ctxt)
 
static unsigned int rest_of_handle_cse_after_global_opts (void)
 
rtl_opt_passmake_pass_cse_after_global_opts (gcc::context *ctxt)
 

Variables

static int max_qty
 
static int next_qty
 
static struct qty_table_elemqty_table
 
static rtx_insnthis_insn
 
static bool optimize_this_for_speed_p
 
static struct reg_eqv_elemreg_eqv_table
 
static struct cse_reg_infocse_reg_info_table
 
static unsigned int cse_reg_info_table_size
 
static unsigned int cse_reg_info_table_first_uninitialized
 
static unsigned int cse_reg_info_timestamp
 
static HARD_REG_SET hard_regs_in_table
 
static bool cse_cfg_altered
 
static bool cse_jumps_altered
 
static bool recorded_label_ref
 
static int do_not_record
 
static int hash_arg_in_memory
 
static struct table_elttable [HASH_SIZE]
 
static struct table_eltfree_element_chain
 
static bitmap cse_ebb_live_in
 
static bitmap cse_ebb_live_out
 
static sbitmap cse_visited_basic_blocks
 
static const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER
 

Macro Definition Documentation

◆ CHEAP_REGNO

#define CHEAP_REGNO ( N)
Value:
#define FIXED_REGNO_P(N)
Definition cse.cc:423
#define N
Definition gensupport.cc:202
T * ggc_alloc(ALONE_CXX_MEM_STAT_INFO)
Definition ggc.h:184
#define REGNO_PTR_FRAME_P(REGNUM)
Definition rtl.h:4081
#define HARD_REGISTER_NUM_P(REG_NO)
Definition rtl.h:1973
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'.   

Referenced by approx_reg_cost().

◆ CHEAPER

#define CHEAPER ( X,
Y )    (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
Compare table_elt X and Y and return true iff X is cheaper than Y.   

Referenced by find_reg_offset_for_const(), and insert_with_costs().

◆ COST

#define COST ( X,
MODE )    (REG_P (X) ? 0 : notreg_cost (X, MODE, SET, 1))

◆ COST_IN

#define COST_IN ( X,
MODE,
OUTER,
OPNO )    (REG_P (X) ? 0 : notreg_cost (X, MODE, OUTER, OPNO))

Referenced by fold_rtx().

◆ FIXED_REGNO_P

#define FIXED_REGNO_P ( N)
Value:
char global_regs[FIRST_PSEUDO_REGISTER]
Definition reginfo.cc:92
#define fixed_regs
Definition hard-reg-set.h:470
#define HARD_FRAME_POINTER_REGNUM
Definition rtl.h:3835
Determine whether register number N is considered a fixed register for the
purpose of approximating register costs.
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.   

Referenced by make_regs_eqv().

◆ HASH_MASK

#define HASH_MASK   (HASH_SIZE - 1)

Referenced by HASH(), and SAFE_HASH().

◆ HASH_SHIFT

#define HASH_SHIFT   5
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.   

Referenced by HASH(), and SAFE_HASH().

◆ HASH_SIZE

◆ REG_IN_TABLE

#define REG_IN_TABLE ( N)    (get_cse_reg_info (N)->reg_in_table)
Get the point at which REG was recorded in the table.   

Referenced by cse_insn(), exp_equiv_p(), insert_regs(), mention_regs(), and rehash_using_reg().

◆ REG_QTY

◆ REG_TICK

#define REG_TICK ( N)    (get_cse_reg_info (N)->reg_tick)
Get the number of times this register has been updated in this
basic block.   

Referenced by exp_equiv_p(), insert_regs(), invalidate_for_call(), invalidate_reg(), mention_regs(), and rehash_using_reg().

◆ REGNO_QTY_VALID_P

#define REGNO_QTY_VALID_P ( N)    (REG_QTY (N) >= 0)
Determine if the quantity number for register X represents a valid index
into the qty_table.   

Referenced by canon_reg(), cse_insn(), cse_process_note_1(), delete_reg_equiv(), equiv_constant(), fold_rtx(), insert_regs(), insert_with_costs(), make_regs_eqv(), mention_regs(), merge_equiv_classes(), and try_back_substitute_reg().

◆ RTL_HOOKS_GEN_LOWPART

#define RTL_HOOKS_GEN_LOWPART   gen_lowpart_if_possible

◆ SUBREG_TICKED

#define SUBREG_TICKED ( N)    (get_cse_reg_info (N)->subreg_ticked)
Get the SUBREG set at the last increment to REG_TICK (-1 if not a
SUBREG).   

Referenced by invalidate_for_call(), invalidate_reg(), and mention_regs().

Function Documentation

◆ add_to_set()

static void add_to_set ( vec< struct set > * sets,
rtx x,
bool is_fake_set )
inlinestatic
Add an entry containing RTL X into SETS.  IS_FAKE_SET is true if X is
an artifical set that has been created to describe part of an insn's
effect.   

References set::is_fake_set, and set::rtl.

Referenced by find_sets_in_insn().

◆ approx_reg_cost()

static int approx_reg_cost ( const_rtx x)
static
Return an estimate of the cost of the registers used in an rtx.
This is mostly the number of different REG expressions in the rtx;
however for some exceptions like fixed registers we use a cost of
0.  If any other hard register reference occurs, return MAX_COST.   

References CHEAP_REGNO, table_elt::cost, FOR_EACH_SUBRTX, GET_MODE, ggc_alloc(), MAX_COST, REG_P, REGNO, and targetm.

Referenced by cse_insn(), and insert().

◆ canon_asm_operands()

static void canon_asm_operands ( rtx x,
rtx_insn * insn )
static
Subroutine of canonicalize_insn.  X is an ASM_OPERANDS in INSN.   

References ASM_OPERANDS_INPUT, ASM_OPERANDS_INPUT_LENGTH, canon_reg(), HARD_REGISTER_P, i, REG_P, and validate_change().

Referenced by canonicalize_insn().

◆ canon_hash()

static unsigned canon_hash ( rtx x,
machine_mode mode )
inlinestatic
Hash an rtx X for cse via hash_rtx.
Stores 1 in do_not_record if any subexpression is volatile.
Stores 1 in hash_arg_in_memory if X contains a mem rtx which
does not have the MEM_READONLY_P flag set.   

References do_not_record, hash_arg_in_memory, hash_rtx(), and table_elt::mode.

Referenced by HASH().

◆ canon_reg()

static rtx canon_reg ( rtx x,
rtx_insn * insn )
static
Canonicalize an expression:
replace each register reference inside it
with the "oldest" equivalent register.

If INSN is nonzero validate_change is used to ensure that INSN remains valid
after we make our substitution.  The calls are made with IN_GROUP nonzero
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.   

References CASE_CONST_ANY, gen_rtx_REG(), GET_CODE, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), i, qty_table, REG_QTY, REGNO, REGNO_QTY_VALID_P, regno_reg_rtx, validate_canon_reg(), XEXP, XVECEXP, and XVECLEN.

Referenced by canon_asm_operands(), canonicalize_insn(), cse_insn(), cse_process_note_1(), fold_rtx(), and validate_canon_reg().

◆ canonicalize_insn()

static void canonicalize_insn ( rtx_insn * insn,
vec< struct set > * psets )
static
Where possible, substitute every register reference in the N_SETS
number of SETS in INSN with the canonical register.

Register canonicalization propagatest the earliest register (i.e.
one that is set before INSN) with the same value.  This is a very
useful, simple form of CSE, to clean up warts from expanding GIMPLE
to RTL.  For instance, a CONST for an address is usually expanded
multiple times to loads into different registers, thus creating many
subexpressions of the form:

(set (reg1) (some_const))
(set (mem (... reg1 ...) (thing)))
(set (reg2) (some_const))
(set (mem (... reg2 ...) (thing)))

After canonicalizing, the code takes the following form:

(set (reg1) (some_const))
(set (mem (... reg1 ...) (thing)))
(set (reg2) (some_const))
(set (mem (... reg1 ...) (thing)))

The set to reg2 is now trivially dead, and the memory reference (or
address, or whatever) may be a candidate for further CSEing.

In this function, the result of apply_change_group can be ignored;
see canon_reg.   

References apply_change_group(), CALL_INSN_FUNCTION_USAGE, CALL_P, canon_asm_operands(), canon_reg(), DEBUG_INSN_P, df_notes_rescan(), find_reg_note(), fold_rtx(), GET_CODE, ggc_alloc(), i, MEM_P, NULL_RTX, PATTERN(), REG_NOTES, REG_P, REGNO, remove_note(), set::rtl, rtx_equal_p(), SET, SET_DEST, SET_SRC, set::src, validate_change(), XEXP, XVECEXP, XVECLEN, and y.

Referenced by cse_insn().

◆ check_dependence()

static bool check_dependence ( const_rtx x,
rtx exp,
machine_mode mode,
rtx addr )
static
Check whether an anti dependence exists between X and EXP.  MODE and
ADDR are as for canon_anti_dependence.   

References canon_anti_dependence(), exp(), FOR_EACH_SUBRTX, ggc_alloc(), MEM_P, and table_elt::mode.

Referenced by invalidate().

◆ check_for_label_ref()

static bool check_for_label_ref ( rtx_insn * insn)
static
Return true if the pattern of INSN uses a LABEL_REF for which
there isn't a REG_LABEL_OPERAND note.   

References find_reg_note(), FOR_EACH_SUBRTX, GET_CODE, ggc_alloc(), INSN_UID(), JUMP_P, label_is_jump_target_p(), LABEL_P, label_ref_label(), LABEL_REF_NONLOCAL_P, and PATTERN().

Referenced by cse_extended_basic_block().

◆ compute_const_anchors()

static bool compute_const_anchors ( rtx cst,
HOST_WIDE_INT * lower_base,
HOST_WIDE_INT * lower_offs,
HOST_WIDE_INT * upper_base,
HOST_WIDE_INT * upper_offs )
static
Compute upper and lower anchors for CST.  Also compute the offset of CST
from these anchors/bases such that *_BASE + *_OFFS = CST.  Return false iff
CST is equal to an anchor.   

References ggc_alloc(), targetm, and UINTVAL.

Referenced by insert_const_anchors(), and try_const_anchors().

◆ count_reg_usage()

static void count_reg_usage ( rtx x,
int * counts,
rtx dest,
int incr )
static
Count the number of times registers are used (not set) in X.
COUNTS is an array in which we accumulate the count, INCR is how much
we count each register usage.

Don't count a usage of DEST, which is the SET_DEST of a SET which
contains X in its SET_SRC.  This is because such a SET does not
modify the liveness of DEST.
DEST is set to pc_rtx for a trapping insn, or for an insn with side effects.
We must then count uses of a SET_DEST regardless, because the insn can't be
deleted here.   

References ASM_OPERANDS_INPUT, ASM_OPERANDS_INPUT_LENGTH, CALL_INSN_FUNCTION_USAGE, CASE_CONST_ANY, cfun, count_reg_usage(), find_reg_equal_equiv_note(), gcc_unreachable, GET_CODE, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), i, insn_nothrow_p(), MEM_P, NULL_RTX, PATTERN(), pc_rtx, REG_NOTE_KIND, REG_P, REGNO, SET, SET_DEST, SET_SRC, side_effects_p(), XEXP, XVECEXP, and XVECLEN.

Referenced by count_reg_usage(), and delete_trivially_dead_insns().

◆ count_stores()

static void count_stores ( rtx x,
const_rtx set,
void * data )
static
Count the number of stores into pseudo.  Callback for note_stores.   

References ggc_alloc(), REG_P, and REGNO.

Referenced by delete_trivially_dead_insns().

◆ cse_cc_succs()

static machine_mode cse_cc_succs ( basic_block bb,
basic_block orig_bb,
rtx cc_reg,
rtx cc_src,
bool can_change_mode )
static
BB is a basic block which finishes with CC_REG as a condition code
register which is set to CC_SRC.  Look through the successors of BB
to find blocks which have a single predecessor (i.e., this one),
and look through those blocks for an assignment to CC_REG which is
equivalent to CC_SRC.  CAN_CHANGE_MODE indicates whether we are
permitted to change the mode of CC_SRC to a compatible mode.  This
returns VOIDmode if no equivalent assignments were found.
Otherwise it returns the mode which CC_SRC should wind up with.
ORIG_BB should be the same as BB in the outermost cse_cc_succs call,
but is passed unmodified down to recursive calls in order to prevent
endless recursion.

The main complexity in this function is handling the mode issues.
We may have more than one duplicate which we can eliminate, and we
try to find a mode which will work for multiple duplicates.   

References BB_END, BB_HEAD, cfun, cse_cc_succs(), cse_cfg_altered, cse_change_cc_mode_insns(), delete_insn(), delete_insn_and_edges(), EDGE_COMPLEX, EDGE_COUNT, end(), EXIT_BLOCK_PTR_FOR_FN, FOR_EACH_EDGE, gcc_assert, gen_rtx_REG(), GET_CODE, GET_MODE, ggc_alloc(), i, INSN_P, insns, modes, modified_in_p(), NEXT_INSN(), NULL_RTX, PUT_MODE(), REG_P, reg_set_p(), REGNO, rtx_equal_p(), SET_DEST, SET_SRC, single_set(), basic_block_def::succs, targetm, and XEXP.

Referenced by cse_cc_succs(), and cse_condition_code_reg().

◆ cse_change_cc_mode()

static void cse_change_cc_mode ( subrtx_ptr_iterator::array_type & array,
rtx * loc,
rtx_insn * insn,
rtx newreg )
static
If LOC contains references to NEWREG in a different mode, change them
to use NEWREG instead.   

References FOR_EACH_SUBRTX_PTR, GET_MODE, ggc_alloc(), REG_P, REGNO, and validate_change().

Referenced by cse_change_cc_mode_insn().

◆ cse_change_cc_mode_insn()

static void cse_change_cc_mode_insn ( rtx_insn * insn,
rtx newreg )
static
Change the mode of any reference to the register REGNO (NEWREG) to
GET_MODE (NEWREG) in INSN.   

References apply_change_group(), cse_change_cc_mode(), gcc_assert, ggc_alloc(), INSN_P, PATTERN(), and REG_NOTES.

Referenced by cse_change_cc_mode_insns(), and cse_condition_code_reg().

◆ cse_change_cc_mode_insns()

static void cse_change_cc_mode_insns ( rtx_insn * start,
rtx_insn * end,
rtx newreg )
static
Change the mode of any reference to the register REGNO (NEWREG) to
GET_MODE (NEWREG), starting at START.  Stop before END.  Stop at
any instruction which modifies NEWREG.   

References cse_change_cc_mode_insn(), end(), ggc_alloc(), INSN_P, NEXT_INSN(), and reg_set_p().

Referenced by cse_cc_succs(), and cse_condition_code_reg().

◆ cse_condition_code_reg()

static void cse_condition_code_reg ( void )
static
If we have a fixed condition code register (or two), walk through
the instructions and try to eliminate duplicate assignments.   

References BB_END, BB_HEAD, cfun, cse_cc_succs(), cse_change_cc_mode_insn(), cse_change_cc_mode_insns(), FOR_EACH_BB_FN, gcc_assert, gen_rtx_REG(), GET_MODE, ggc_alloc(), INSN_P, INVALID_REGNUM, JUMP_P, modified_between_p(), NEXT_INSN(), NULL, NULL_RTX, PATTERN(), PREV_INSN(), REG_P, reg_referenced_p(), reg_set_p(), REGNO, SET_DEST, SET_SRC, single_set(), and targetm.

Referenced by rest_of_handle_cse2().

◆ cse_dump_path()

static void cse_dump_path ( struct cse_basic_block_data * data,
int nsets,
FILE * f )
static
Dump the path in DATA to file F.  NSETS is the number of sets
in the path.   

References fputc(), and ggc_alloc().

Referenced by cse_main().

◆ cse_extended_basic_block()

◆ cse_find_path()

static bool cse_find_path ( basic_block first_bb,
struct cse_basic_block_data * data,
int follow_jumps )
static
Find a path in the CFG, starting with FIRST_BB to perform CSE on.

DATA is a pointer to a struct cse_basic_block_data, that is used to
describe the path.
It is filled with a queue of basic blocks, starting with FIRST_BB
and following a trace through the CFG.

If all paths starting at FIRST_BB have been followed, or no new path
starting at FIRST_BB can be constructed, this function returns FALSE.
Otherwise, DATA->path is filled and the function returns TRUE indicating
that a path to follow was found.

If FOLLOW_JUMPS is false, the maximum path length is 1 and the only
block in the path will be FIRST_BB.   

References any_condjump_p(), BB_END, bitmap_bit_p, bitmap_set_bit, BRANCH_EDGE, cfun, cse_visited_basic_blocks, EDGE_COUNT, EXIT_BLOCK_PTR_FOR_FN, FALLTHRU_EDGE, find_edge(), follow_jumps(), gcc_assert, ggc_alloc(), basic_block_def::index, NULL, single_pred_p(), single_succ_edge(), single_succ_p(), and basic_block_def::succs.

Referenced by cse_main().

◆ cse_insn()

static void cse_insn ( rtx_insn * insn)
static
Main function of CSE.
First simplify sources and addresses of all assignments
in the instruction, using previously-computed equivalents values.
Then install the new sources and destinations in the table
of available values.   

References alias_set_subset_of(), apply_change_group(), approx_reg_cost(), BITS_PER_WORD, CALL_INSN_FUNCTION_USAGE, CALL_P, can_throw_internal(), canon_reg(), canonicalize_insn(), cfun, condjump_p(), CONST_INT_P, const_vec_duplicate_p(), CONSTANT_P, copy_rtx(), table_elt::cost, COST, crtl, cse_cfg_altered, cse_jumps_altered, delete_insn_and_edges(), df_notes_rescan(), do_not_record, emit_jump_insn_before(), END_REGNO(), table_elt::exp, exp_equiv_p(), find_reg_note(), find_sets_in_insn(), table_elt::first_same_value, FLOAT_MODE_P, flush_hash_table(), fold_rtx(), FOR_EACH_WIDER_MODE, force_const_mem(), GEN_INT, gen_lowpart, gen_rtx_REG(), GET_CODE, GET_MODE, GET_MODE_CLASS, GET_MODE_INNER, GET_MODE_PRECISION(), GET_MODE_SIZE(), GET_RTX_CLASS, ggc_alloc(), HASH(), hash_arg_in_memory, HOST_BITS_PER_WIDE_INT, HOST_WIDE_INT_1, HOST_WIDE_INT_M1, HOST_WIDE_INT_M1U, i, table_elt::in_memory, insert(), insert_const_anchors(), insert_regs(), INSN_CODE, insn_nothrow_p(), INTVAL, invalidate(), invalidate_dest(), invalidate_for_call(), invalidate_from_clobbers(), invalidate_from_sets_and_clobbers(), invalidate_memory(), is_int_mode(), JUMP_LABEL, known_ge, LABEL_NUSES, LABEL_REF_NONLOCAL_P, load_extend_op(), lookup(), MAX_COST, MEM_ALIAS_SET, MEM_EXPR, MEM_P, MEM_READONLY_P, mention_regs(), merge_equiv_classes(), qty_table_elem::mode, table_elt::mode, new_mode(), table_elt::next_same_value, NULL, NULL_RTX, paradoxical_subreg_p(), partial_subreg_p(), PATTERN(), pc_rtx, preferable(), table_elt::prev_same_value, PUT_CODE, PUT_MODE(), qty_table, refs_same_for_tbaa_p(), REG_IN_TABLE, REG_NOTES, REG_P, REG_QTY, table_elt::regcost, REGNO, REGNO_QTY_VALID_P, regno_reg_rtx, rehash_using_reg(), table_elt::related_value, remove_invalid_refs(), remove_note(), RTL_CONST_OR_PURE_CALL_P, RTX_AUTOINC, rtx_equal_p(), SCALAR_INT_MODE_P, SET_DEST, SET_SRC, set_unique_reg_note(), shift, side_effects_p(), simplify_gen_subreg(), stack_pointer_rtx, subreg_lowpart_offset(), SUBREG_REG, targetm, this_insn, trunc_int_for_mode(), try_back_substitute_reg(), try_const_anchors(), use_related_value(), validate_change(), validate_unshare_change(), XEXP, XVECEXP, XVECLEN, and y.

Referenced by cse_extended_basic_block().

◆ cse_main()

static int cse_main ( rtx_insn * f,
int nregs )
static
Perform cse on the instructions of a function.
F is the first instruction.
NREGS is one plus the highest pseudo-reg number used in the instruction.

Return 2 if jump optimizations should be redone due to simplifications
in conditional jump instructions.
Return 1 if the CFG should be cleaned up because it has been modified.
Return 0 otherwise.   

References BASIC_BLOCK_FOR_FN, bitmap_bit_p, bitmap_clear(), CDI_DOMINATORS, cfun, cse_cfg_altered, cse_dump_path(), cse_extended_basic_block(), cse_find_path(), cse_jumps_altered, cse_prescan_path(), cse_rtl_hooks, cse_visited_basic_blocks, df_analyze(), DF_DEFER_INSN_RESCAN, DF_LR_RUN_DCE, df_note_add_problem(), df_set_flags(), dump_file, end_alias_analysis(), free(), free_dominance_info(), general_rtl_hooks, get_insns(), ggc_alloc(), i, init_alias_analysis(), init_cse_reg_info(), init_recog(), last_basic_block_for_fn, max_qty, max_reg_num(), NULL, pre_and_rev_post_order_compute(), recorded_label_ref, reg_eqv_table, reg_scan(), sbitmap_alloc(), and sbitmap_free().

Referenced by rest_of_handle_cse(), rest_of_handle_cse2(), and rest_of_handle_cse_after_global_opts().

◆ cse_prescan_path()

static void cse_prescan_path ( struct cse_basic_block_data * data)
static
Scan to the end of the path described by DATA.  Return an estimate of
the total number of SETs of all insns in the path.   

References FOR_BB_INSNS, GET_CODE, ggc_alloc(), INSN_P, PATTERN(), and XVECLEN.

Referenced by cse_main().

◆ cse_process_note()

static rtx cse_process_note ( rtx x)
static
Process X, part of the REG_NOTES of an insn.  Replace any registers in it
with either an equivalent constant or the canonical form of the register.
Only replace addresses if the containing MEM remains valid.   

References cse_process_note_1(), NULL, NULL_RTX, and simplify_replace_fn_rtx().

Referenced by cse_extended_basic_block(), and cse_process_note_1().

◆ cse_process_note_1()

static rtx cse_process_note_1 ( rtx x,
const_rtx ,
void *  )
static
A simplify_replace_fn_rtx callback for cse_process_note.  Process X,
part of the REG_NOTES of an insn.  Replace any registers with either
an equivalent constant or the canonical form of the register.
Only replace addresses if the containing MEM remains valid.

Return the replacement for X, or null if it should be simplified
recursively.   

References canon_reg(), CONSTANT_P, copy_rtx(), cse_process_note(), gen_lowpart, GET_MODE, ggc_alloc(), i, MEM_P, NULL, NULL_RTX, qty_table, REG_P, REG_QTY, REGNO, REGNO_QTY_VALID_P, validate_change(), and XEXP.

Referenced by cse_process_note().

◆ delete_reg_equiv()

static void delete_reg_equiv ( unsigned int reg)
static

◆ delete_trivially_dead_insns()

int delete_trivially_dead_insns ( rtx_insn * insns,
int nreg )
Scan all the insns and delete any that are dead; i.e., they store a register
that is never used or they copy a register to itself.

This is used to remove insns made obviously dead by cse, loop or other
optimizations.  It improves the heuristics in loop since it won't try to
move dead invariants out of loops or make givs for dead quantities.  The
remaining passes of the compilation are also sped up.   

References asm_noperands(), count_reg_usage(), count_stores(), cse_cfg_altered, dbg_cnt(), DEBUG_BIND_INSN_P, DEBUG_EXPR_TREE_DECL, DEBUG_INSN_P, DEBUG_MARKER_INSN_P, delete_insn_and_edges(), df_insn_rescan(), dump_file, emit_debug_insn_before(), free(), gen_rtx_UNKNOWN_VAR_LOC, gen_rtx_VAR_LOCATION(), get_last_insn(), GET_MODE, ggc_alloc(), insn_live_p(), INSN_P, INSN_VAR_LOCATION_DECL, INSN_VAR_LOCATION_LOC, insns, is_dead_debug_insn(), is_dead_reg(), make_debug_expr_from_rtl(), MAY_HAVE_DEBUG_BIND_INSNS, NEXT_INSN(), note_stores(), NULL, NULL_RTX, PATTERN(), pic_offset_table_rtx, PREV_INSN(), REGNO, reload_completed, replace_dead_reg(), replacements, SET_DEST, SET_SRC, side_effects_p(), simplify_replace_fn_rtx(), single_set(), timevar_pop(), timevar_push(), TREE_VISITED, and VAR_INIT_STATUS_INITIALIZED.

Referenced by cleanup_cfg(), fwprop_done(), ira(), rest_of_handle_cse2(), and rest_of_handle_cse_after_global_opts().

◆ dump_class()

DEBUG_FUNCTION void dump_class ( struct table_elt * classp)
extern
Dump the expressions in the equivalence class indicated by CLASSP.
This function is used only for debugging.   

References table_elt::exp, ggc_alloc(), table_elt::next_same_value, and print_rtl().

◆ equiv_constant()

◆ exp_equiv_p()

bool exp_equiv_p ( const_rtx x,
const_rtx y,
int validate,
bool for_gcse )

◆ find_comparison_args()

static enum rtx_code find_comparison_args ( enum rtx_code code,
rtx * parg1,
rtx * parg2,
machine_mode * pmode1,
machine_mode * pmode2 )
static
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 (reg:CC CC_REG) and
*PARG2 was (const_int 0), *PARG1 and *PARG2 will be set to the objects that
were compared to produce (reg:CC CC_REG).

The return value is the comparison operator and is either the code of
A or the code corresponding to the inverse of the comparison.   

References hash_set< KeyId, Lazy, Traits >::add(), COMPARISON_P, const0_rtx, CONST0_RTX, table_elt::exp, exp_equiv_p(), table_elt::first_same_value, fold_rtx(), GET_CODE, GET_MODE, GET_MODE_CLASS, ggc_alloc(), table_elt::is_const, lookup(), table_elt::next_same_value, NULL, REAL_VALUE_NEGATIVE, REAL_VALUE_TYPE, reversed_comparison_code(), rtx_addr_can_trap_p(), SAFE_HASH(), SCALAR_FLOAT_MODE_P, STORE_FLAG_VALUE, val_signbit_known_set_p(), visited, and XEXP.

Referenced by fold_rtx(), and record_jump_equiv().

◆ find_reg_offset_for_const()

static rtx find_reg_offset_for_const ( struct table_elt * anchor_elt,
HOST_WIDE_INT offs,
unsigned * old )
static
We need to express ANCHOR_ELT->exp + OFFS.  Walk the equivalence list of
ANCHOR_ELT and see if offsetting any of the entries by OFFS would create a
valid expression.  Return the cheapest and oldest of such expressions.  In
*OLD, return how old the resulting expression is compared to the other
equivalent expressions.   

References CHEAPER, table_elt::exp, exp_equiv_p(), GET_CODE, GET_MODE, ggc_alloc(), IN_RANGE, INTVAL, table_elt::next_same_value, NULL, NULL_RTX, plus_constant(), REG_P, targetm, and XEXP.

Referenced by try_const_anchors().

◆ find_sets_in_insn()

static int find_sets_in_insn ( rtx_insn * insn,
vec< struct set > * psets )
static
Record all the SETs in this instruction into SETS_PTR,
and return the number of recorded sets.   

References add_to_set(), CONST_VECTOR_ELT, const_vector_encoded_nelts(), gcc_assert, GET_CODE, GET_MODE, GET_MODE_CLASS, GET_MODE_NUNITS(), ggc_alloc(), i, known_eq, PATTERN(), pc_rtx, SET, SET_DEST, SET_SRC, simplify_gen_vec_select(), set::src, SUBREG_P, XVECEXP, XVECLEN, and y.

Referenced by cse_insn().

◆ fixed_base_plus_p()

static bool fixed_base_plus_p ( rtx x)
static
Nonzero if X has the form (PLUS frame-pointer integer).   

References arg_pointer_rtx, CONST_INT_P, fixed_base_plus_p(), fixed_regs, frame_pointer_rtx, GET_CODE, ggc_alloc(), hard_frame_pointer_rtx, and XEXP.

Referenced by fixed_base_plus_p(), and insert_with_costs().

◆ flush_hash_table()

static void flush_hash_table ( void )
static
Flush the entire hash table.   

References table_elt::exp, ggc_alloc(), HASH_SIZE, i, invalidate(), REG_P, remove_from_table(), and table.

Referenced by cse_extended_basic_block(), and cse_insn().

◆ fold_rtx()

static rtx fold_rtx ( rtx x,
rtx_insn * insn )
static
If X is a nontrivial arithmetic operation on an argument for which
a constant value can be determined, return the result of operating
on that value, as a constant.  Otherwise, return X, possibly with
one or more operands changed to a forward-propagated constant.

If X is a register whose contents are known, we do NOT return
those contents here; equiv_constant is called to perform that task.
For SUBREGs and MEMs, we do that both here and in equiv_constant.

INSN is the insn that we may be modifying.  If it is 0, make a copy
of X before modifying it.   

References apply_change_group(), ASM_OPERANDS_INPUT, ASM_OPERANDS_INPUT_LENGTH, canon_reg(), canonicalize_change_group(), CASE_CONST_ANY, changed, comparison_dominates_p(), const0_rtx, CONST0_RTX, const_double_from_real_value(), CONST_INT_P, const_true_rtx, CONSTANT_P, copy_rtx(), table_elt::cost, COST, COST_IN, equiv_constant(), table_elt::exp, exp_equiv_p(), false_rtx, find_comparison_args(), table_elt::first_same_value, FLOAT_MODE_P, fold_rtx(), GEN_INT, gen_int_shift_amount(), GET_CODE, GET_MODE, GET_MODE_CLASS, GET_MODE_UNIT_BITSIZE, GET_MODE_UNIT_PRECISION, GET_RTX_CLASS, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), HAVE_POST_DECREMENT, HAVE_POST_INCREMENT, HAVE_PRE_DECREMENT, HAVE_PRE_INCREMENT, HOST_BITS_PER_WIDE_INT, HOST_WIDE_INT_1, i, INTVAL, label_ref_label(), lookup(), lookup_as_function(), lowpart_subreg(), qty_table_elem::mode, table_elt::mode, table_elt::next_same_value, NO_FUNCTION_CSE, NULL, NULL_RTX, plus_constant(), poly_int_rtx_p(), pow2p_hwi(), qty_table, reg_mentioned_p(), REG_P, REG_QTY, REGNO, REGNO_QTY_VALID_P, reverse_condition(), RTX_BIN_ARITH, RTX_BITFIELD_OPS, RTX_COMM_ARITH, RTX_COMM_COMPARE, RTX_COMPARE, rtx_equal_p(), RTX_OBJ, RTX_TERNARY, RTX_UNARY, SAFE_HASH(), SCALAR_FLOAT_MODE_P, SHIFT_COUNT_TRUNCATED, side_effects_p(), simplify_binary_operation(), simplify_gen_binary(), simplify_relational_operation(), simplify_ternary_operation(), simplify_unary_operation(), true_rtx, validate_change(), validate_unshare_change(), vec_series_lowpart_p(), VECTOR_MODE_P, XEXP, and y.

Referenced by canonicalize_insn(), cse_insn(), find_comparison_args(), fold_rtx(), and record_jump_equiv().

◆ get_cse_reg_info()

static struct cse_reg_info * get_cse_reg_info ( unsigned int regno)
inlinestatic
Find a cse_reg_info entry for REGNO.   

References cse_reg_info_table, cse_reg_info_timestamp, get_cse_reg_info_1(), and cse_reg_info::timestamp.

◆ get_cse_reg_info_1()

static void get_cse_reg_info_1 ( unsigned int regno)
static

◆ HASH()

static unsigned HASH ( rtx x,
machine_mode mode )
inlinestatic
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).   

References canon_hash(), ggc_alloc(), HASH_MASK, HASH_SHIFT, REG_P, REG_QTY, and REGNO.

Referenced by cse_insn(), insert_const_anchor(), invalidate_reg(), merge_equiv_classes(), record_jump_cond(), and try_const_anchors().

◆ hash_rtx()

unsigned hash_rtx ( const_rtx x,
machine_mode mode,
int * do_not_record_p,
int * hash_arg_in_memory_p,
bool have_reg_qty,
hash_rtx_callback_function cb )
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_P if any subexpression is volatile.

If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
a MEM rtx which does not have the MEM_READONLY_P flag 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.

Call CB on each rtx if CB is not NULL.
When the callback returns true, we continue with the new rtx.   

References arg_pointer_rtx, ASM_OPERANDS_INPUT, ASM_OPERANDS_INPUT_CONSTRAINT, ASM_OPERANDS_INPUT_LENGTH, ASM_OPERANDS_OUTPUT_CONSTRAINT, ASM_OPERANDS_OUTPUT_IDX, ASM_OPERANDS_TEMPLATE, CODE_LABEL_NUMBER, CONST_DOUBLE_HIGH, CONST_DOUBLE_LOW, CONST_DOUBLE_REAL_VALUE, CONST_FIXED_VALUE, CONST_POLY_INT_COEFFS, CONST_VECTOR_ENCODED_ELT, const_vector_encoded_nelts(), CONST_WIDE_INT_ELT, CONST_WIDE_INT_NUNITS, fixed_hash(), fixed_regs, frame_pointer_rtx, gcc_unreachable, GET_CODE, GET_MODE, GET_MODE_CLASS, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), global_regs, hard_frame_pointer_rtx, hash_rtx(), hash_rtx_string(), i, INTVAL, label_ref_label(), MEM_P, MEM_READONLY_P, MEM_VOLATILE_P, table_elt::mode, NULL, NUM_POLY_INT_COEFFS, pic_offset_table_rtx, real_hash(), REG_P, REG_QTY, REGNO, reload_completed, stack_pointer_rtx, SUBREG_BYTE, SUBREG_REG, TARGET_SUPPORTS_WIDE_INT, targetm, XEXP, XINT, XSTR, XVECEXP, and XVECLEN.

Referenced by canon_hash(), invariant_group_base_hasher::hash(), pre_ldst_expr_hasher::hash(), st_expr_hasher::hash(), hash_expr(), hash_expr(), hash_invariant_expr_1(), hash_rtx(), ldst_entry(), safe_hash(), st_expr_entry(), and temp_slot_address_compute_hash().

◆ hash_rtx_string()

static unsigned hash_rtx_string ( const char * ps)
inlinestatic
Hash a string.  Just add its bytes up.   

References ggc_alloc().

Referenced by hash_rtx().

◆ have_eh_succ_edges()

static bool have_eh_succ_edges ( basic_block bb)
static
Return true if BB has exception handling successor edges.   

References FOR_EACH_EDGE, ggc_alloc(), and basic_block_def::succs.

Referenced by cse_extended_basic_block().

◆ init_cse_reg_info()

static void init_cse_reg_info ( unsigned int nregs)
static

◆ insert() [1/2]

static struct table_elt * insert ( rtx x,
struct table_elt * classp,
unsigned int hash,
machine_mode mode )
static
Wrap insert_with_costs by passing the default costs.   

References approx_reg_cost(), COST, ggc_alloc(), insert_with_costs(), and table_elt::mode.

◆ insert() [2/2]

static struct table_elt * insert ( rtx ,
struct table_elt * ,
unsigned ,
machine_mode  )
static

◆ insert_const_anchor()

static void insert_const_anchor ( HOST_WIDE_INT anchor,
rtx reg,
HOST_WIDE_INT offs,
machine_mode mode )
static
Insert the equivalence between ANCHOR and (REG + OFF) in mode MODE.   

References COST, exp(), gen_int_mode(), ggc_alloc(), HASH(), insert(), insert_with_costs(), lookup(), mention_regs(), table_elt::mode, NULL, and plus_constant().

Referenced by insert_const_anchors().

◆ insert_const_anchors()

static void insert_const_anchors ( rtx reg,
rtx cst,
machine_mode mode )
static
The constant CST is equivalent to the register REG.  Create
equivalences between the two anchors of CST and the corresponding
register-offset expressions using REG.   

References compute_const_anchors(), ggc_alloc(), insert_const_anchor(), and table_elt::mode.

Referenced by cse_insn().

◆ insert_regs()

static bool insert_regs ( rtx x,
struct table_elt * classp,
bool modified )
static
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 true, 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.

True value means that elements of reg_qty have changed
so X's hash code may be different.   

References gcc_assert, GET_CODE, GET_MODE, ggc_alloc(), insert_regs(), make_new_qty(), make_regs_eqv(), mention_regs(), qty_table_elem::mode, NULL, qty_table, REG_IN_TABLE, REG_P, REG_QTY, REG_TICK, REGNO, REGNO_QTY_VALID_P, and SUBREG_REG.

Referenced by cse_insn(), insert_regs(), mention_regs(), merge_equiv_classes(), and record_jump_cond().

◆ insert_with_costs() [1/2]

static struct table_elt * insert_with_costs ( rtx x,
struct table_elt * classp,
unsigned int hash,
machine_mode mode,
int cost,
int reg_cost )
static
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).  COST is the code of X and reg_cost is the
cost of registers in X.  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.   

References add_to_hard_reg_set(), table_elt::canon_exp, CHEAPER, qty_table_elem::const_insn, CONSTANT_P, table_elt::cost, table_elt::exp, table_elt::first_same_value, fixed_base_plus_p(), free_element_chain, gcc_assert, gen_lowpart, GET_CODE, GET_MODE, get_related_value(), ggc_alloc(), hard_regs_in_table, table_elt::in_memory, insert(), table_elt::is_const, lookup(), qty_table_elem::mode, table_elt::mode, table_elt::next_same_hash, table_elt::next_same_value, NULL, NULL_RTX, table_elt::prev_same_hash, table_elt::prev_same_value, qty_table, REG_P, REG_QTY, table_elt::regcost, REGNO, REGNO_QTY_VALID_P, table_elt::related_value, SAFE_HASH(), table, and this_insn.

◆ insert_with_costs() [2/2]

static struct table_elt * insert_with_costs ( rtx ,
struct table_elt * ,
unsigned ,
machine_mode ,
int ,
int  )
static

Referenced by insert(), and insert_const_anchor().

◆ insn_live_p()

static bool insn_live_p ( rtx_insn * insn,
int * counts )
static

◆ invalidate()

static void invalidate ( rtx x,
machine_mode full_mode )
static
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.   

References table_elt::canon_exp, canon_rtx(), check_dependence(), table_elt::exp, gcc_unreachable, get_addr(), GET_CODE, GET_MODE, ggc_alloc(), HASH_SIZE, i, table_elt::in_memory, invalidate(), invalidate_reg(), table_elt::next_same_hash, remove_from_table(), SUBREG_REG, table, XEXP, XVECEXP, and XVECLEN.

Referenced by ipa_polymorphic_call_context::combine_with(), cse_extended_basic_block(), cse_insn(), flush_hash_table(), invalidate(), invalidate_dest(), invalidate_from_clobbers(), invalidate_from_sets_and_clobbers(), and move2add_note_store().

◆ invalidate_dest()

static void invalidate_dest ( rtx dest)
static
Invalidate DEST.  Used when DEST is not going to be added
into the hash table for some reason, e.g. do_not_record
flagged on it.   

References GET_CODE, GET_MODE, ggc_alloc(), invalidate(), MEM_P, REG_P, and XEXP.

Referenced by cse_insn().

◆ invalidate_for_call()

static void invalidate_for_call ( rtx_insn * insn)
static

◆ invalidate_from_clobbers()

static void invalidate_from_clobbers ( rtx_insn * insn)
static
Perform invalidation on the basis of everything about INSN,
except for invalidating the actual places that are SET in it.
This includes the places CLOBBERed, and anything that might
alias with something that is SET or CLOBBERed.   

References GET_CODE, GET_MODE, ggc_alloc(), i, invalidate(), MEM_P, PATTERN(), REG_P, XEXP, XVECEXP, XVECLEN, and y.

Referenced by cse_insn().

◆ invalidate_from_sets_and_clobbers()

static void invalidate_from_sets_and_clobbers ( rtx_insn * insn)
static
Perform invalidation on the basis of everything about INSN.
This includes the places CLOBBERed, and anything that might
alias with something that is SET or CLOBBERed.   

References CALL_INSN_FUNCTION_USAGE, CALL_P, GET_CODE, GET_MODE, ggc_alloc(), i, invalidate(), PATTERN(), REG_P, SET, SET_DEST, SET_SRC, XEXP, XVECEXP, XVECLEN, and y.

Referenced by cse_insn().

◆ invalidate_memory()

static void invalidate_memory ( void )
static
Remove from the hash table all expressions that reference memory.   

References HASH_SIZE, i, table_elt::in_memory, table_elt::next_same_hash, remove_from_table(), and table.

Referenced by cse_insn().

◆ invalidate_reg()

static void invalidate_reg ( rtx x)
static
Remove from the hash table, or mark as invalid, all expressions whose
values could be altered by storing in register X.   

References CLEAR_HARD_REG_BIT, delete_reg_equiv(), END_REGNO(), table_elt::exp, gcc_assert, GET_CODE, GET_MODE, ggc_alloc(), hard_regs_in_table, HASH(), HASH_SIZE, table_elt::next_same_hash, REG_P, REG_TICK, REGNO, remove_from_table(), remove_pseudo_from_table(), SUBREG_TICKED, table, and TEST_HARD_REG_BIT.

Referenced by invalidate().

◆ is_dead_debug_insn()

static bool is_dead_debug_insn ( const_rtx pat,
int * counts,
rtx * replacements,
bool * seen_repl )
static
Return if DEBUG_INSN pattern PAT needs to be reset because some dead
pseudo doesn't have a replacement.  COUNTS[X] is zero if register X
is dead and REPLACEMENTS[X] is null if it has no replacemenet.
Set *SEEN_REPL to true if we see a dead register that does have
a replacement.   

References FOR_EACH_SUBRTX, ggc_alloc(), is_dead_reg(), NULL_RTX, REGNO, and replacements.

Referenced by delete_trivially_dead_insns().

◆ is_dead_reg()

static bool is_dead_reg ( const_rtx x,
int * counts )
inlinestatic
Return true if X is a dead register.   

References ggc_alloc(), REG_P, and REGNO.

Referenced by delete_trivially_dead_insns(), is_dead_debug_insn(), and set_live_p().

◆ lookup() [1/2]

static struct table_elt * lookup ( rtx x,
unsigned int hash,
machine_mode mode )
static
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.   

References table_elt::exp, exp_equiv_p(), table_elt::mode, table_elt::next_same_hash, REG_P, and table.

◆ lookup() [2/2]

◆ lookup_as_function()

static rtx lookup_as_function ( rtx x,
enum rtx_code code )
static
Look for an expression equivalent to X and with code CODE.
If one is found, return that expression.   

References table_elt::exp, exp_equiv_p(), table_elt::first_same_value, GET_CODE, GET_MODE, ggc_alloc(), lookup(), table_elt::next_same_value, and SAFE_HASH().

Referenced by equiv_constant(), and fold_rtx().

◆ lookup_for_remove() [1/2]

static struct table_elt * lookup_for_remove ( rtx x,
unsigned int hash,
machine_mode mode )
static
Like `lookup' but don't care whether the table element uses invalid regs.
Also ignore discrepancies in the machine mode of a register.   

References table_elt::exp, exp_equiv_p(), table_elt::mode, table_elt::next_same_hash, REG_P, REGNO, and table.

◆ lookup_for_remove() [2/2]

static struct table_elt * lookup_for_remove ( rtx ,
unsigned ,
machine_mode  )
static

◆ make_new_qty()

static void make_new_qty ( unsigned int reg,
machine_mode mode )
static
Say that register REG contains a quantity in mode MODE not in any
register before and initialize that quantity.   

References gcc_assert, ggc_alloc(), max_qty, next_qty, NULL, qty_table, reg_eqv_table, and REG_QTY.

Referenced by insert_regs().

◆ make_pass_cse()

rtl_opt_pass * make_pass_cse ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_cse2()

rtl_opt_pass * make_pass_cse2 ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_cse_after_global_opts()

rtl_opt_pass * make_pass_cse_after_global_opts ( gcc::context * ctxt)

References ggc_alloc().

◆ make_regs_eqv()

static void make_regs_eqv ( unsigned int new_reg,
unsigned int old_reg )
static

◆ mention_regs()

static bool mention_regs ( rtx x)
static
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 true if we have done something that may have changed
the hash code of X.   

References changed, COMPARISON_P, END_REGNO(), GET_CODE, GET_MODE, GET_RTX_FORMAT, GET_RTX_LENGTH, ggc_alloc(), i, insert_regs(), mention_regs(), NULL, REG_IN_TABLE, REG_P, REG_TICK, REGNO, REGNO_QTY_VALID_P, rehash_using_reg(), remove_invalid_refs(), remove_invalid_subreg_refs(), SUBREG_BYTE, SUBREG_REG, SUBREG_TICKED, XEXP, XVECEXP, and XVECLEN.

Referenced by cse_insn(), insert_const_anchor(), insert_regs(), and mention_regs().

◆ merge_equiv_classes()

static void merge_equiv_classes ( struct table_elt * class1,
struct table_elt * class2 )
static
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.   

References table_elt::cost, delete_reg_equiv(), table_elt::exp, exp(), exp_equiv_p(), GET_CODE, ggc_alloc(), HASH(), hash_arg_in_memory, insert(), insert_regs(), MAX_COST, table_elt::mode, table_elt::next_same_value, REG_P, REGNO, REGNO_QTY_VALID_P, rehash_using_reg(), remove_from_table(), and remove_pseudo_from_table().

Referenced by cse_insn(), and record_jump_cond().

◆ new_basic_block()

static void new_basic_block ( void )
static
Clear the hash table and initialize each register with its own quantity,
for a new basic block.   

References CLEAR_HARD_REG_SET, cse_reg_info_timestamp, free_element_chain, hard_regs_in_table, HASH_SIZE, i, last, next_qty, NULL, and table.

Referenced by cse_extended_basic_block().

◆ notreg_cost()

static int notreg_cost ( rtx x,
machine_mode mode,
enum rtx_code outer,
int opno )
static
Internal function, to compute cost when X is not a register; called
from COST macro to keep it simple.   

References GET_CODE, GET_MODE, GET_MODE_SIZE(), ggc_alloc(), is_int_mode(), table_elt::mode, optimize_this_for_speed_p, REG_P, rtx_cost(), subreg_lowpart_p(), SUBREG_REG, and TRULY_NOOP_TRUNCATION_MODES_P.

◆ preferable()

static int preferable ( int cost_a,
int regcost_a,
int cost_b,
int regcost_b )
static
Return a negative value if an rtx A, whose costs are given by COST_A
and REGCOST_A, is more desirable than an rtx B.
Return a positive value if A is less desirable, or 0 if the two are
equally good.   

References ggc_alloc(), and MAX_COST.

Referenced by cse_insn().

◆ record_jump_cond()

static void record_jump_cond ( enum rtx_code code,
machine_mode mode,
rtx op0,
rtx op1 )
static
We know that comparison CODE applied to OP0 and OP1 in MODE is true.
Make any useful entries we can with that information.  Called from
above function and called recursively.   

References CONSTANT_P, do_not_record, equiv_constant(), FLOAT_MODE_P, GET_MODE, ggc_alloc(), HASH(), hash_arg_in_memory, insert(), insert_regs(), lookup(), merge_equiv_classes(), qty_table_elem::mode, table_elt::mode, NULL, NULL_RTX, paradoxical_subreg_p(), partial_subreg_p(), qty_table, record_jump_cond(), record_jump_cond_subreg(), REG_P, REG_QTY, REGNO, rehash_using_reg(), rtx_equal_p(), subreg_lowpart_p(), and SUBREG_REG.

Referenced by record_jump_cond(), and record_jump_equiv().

◆ record_jump_cond_subreg()

static rtx record_jump_cond_subreg ( machine_mode mode,
rtx op )
static
Yet another form of subreg creation.  In this case, we want something in
MODE, and we should assume OP has MODE iff it is naturally modeless.   

References GET_MODE, ggc_alloc(), lowpart_subreg(), and table_elt::mode.

Referenced by record_jump_cond().

◆ record_jump_equiv()

static void record_jump_equiv ( rtx_insn * insn,
bool taken )
static
Given INSN, a jump insn, TAKEN indicates if we are following the
"taken" branch.

In certain cases, this can cause us to add an equivalence.  For example,
if we are following the taken case of
     if (i == 2)
we can add the fact that `i' and '2' are now equivalent.

In any case, we can record that this comparison was passed.  If the same
comparison is seen later, we will know its value.   

References any_condjump_p(), find_comparison_args(), fold_rtx(), gcc_assert, GET_CODE, ggc_alloc(), table_elt::mode, NULL_RTX, pc_rtx, pc_set(), record_jump_cond(), reversed_comparison_code_parts(), SET_SRC, and XEXP.

Referenced by cse_extended_basic_block().

◆ rehash_using_reg()

static void rehash_using_reg ( rtx x)
static
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.   

References table_elt::exp, exp_equiv_p(), GET_CODE, ggc_alloc(), HASH_SIZE, i, table_elt::mode, table_elt::next_same_hash, table_elt::prev_same_hash, REG_IN_TABLE, reg_mentioned_p(), REG_P, REG_TICK, REGNO, SAFE_HASH(), SUBREG_REG, and table.

Referenced by cse_insn(), mention_regs(), merge_equiv_classes(), and record_jump_cond().

◆ remove_from_table() [1/2]

◆ remove_from_table() [2/2]

static void remove_from_table ( struct table_elt * elt,
unsigned int hash )
static
Look in or update the hash table.   
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.   

References table_elt::first_same_value, free_element_chain, ggc_alloc(), HASH_SIZE, table_elt::next_same_hash, table_elt::next_same_value, table_elt::prev_same_hash, table_elt::prev_same_value, table_elt::related_value, and table.

◆ remove_invalid_refs()

static void remove_invalid_refs ( unsigned int regno)
static
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.   

References table_elt::exp, HASH_SIZE, i, table_elt::next_same_hash, refers_to_regno_p(), REG_P, remove_from_table(), and table.

Referenced by cse_insn(), and mention_regs().

◆ remove_invalid_subreg_refs()

static void remove_invalid_subreg_refs ( unsigned int regno,
poly_uint64 offset,
machine_mode mode )
static
Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
and mode MODE.   

References table_elt::exp, exp(), GET_CODE, GET_MODE, GET_MODE_SIZE(), ggc_alloc(), HASH_SIZE, i, table_elt::mode, table_elt::next_same_hash, offset, refers_to_regno_p(), REG_P, REGNO, remove_from_table(), SUBREG_BYTE, SUBREG_REG, and table.

Referenced by mention_regs().

◆ remove_pseudo_from_table() [1/2]

static void remove_pseudo_from_table ( rtx x,
unsigned int hash )
static
Same as above, but X is a pseudo-register.   

References ggc_alloc(), lookup_for_remove(), and remove_from_table().

◆ remove_pseudo_from_table() [2/2]

static void remove_pseudo_from_table ( rtx ,
unsigned  )
static

◆ replace_dead_reg()

static rtx replace_dead_reg ( rtx x,
const_rtx old_rtx,
void * data )
static
Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
Callback for simplify_replace_fn_rtx.   

References GET_MODE, ggc_alloc(), lowpart_subreg(), NULL_RTX, REG_P, REGNO, and replacements.

Referenced by delete_trivially_dead_insns().

◆ rest_of_handle_cse()

static unsigned int rest_of_handle_cse ( void )
static
Perform common subexpression elimination.  Nonzero value from
`cse_main' means that jumps were simplified and some code may now
be unreachable, so do jump optimization again.   

References cleanup_cfg(), CLEANUP_CFG_CHANGED, cse_cfg_altered, cse_main(), cse_not_expected, dump_file, dump_flags, dump_flow_info(), get_insns(), ggc_alloc(), max_reg_num(), rebuild_jump_labels(), timevar_pop(), and timevar_push().

◆ rest_of_handle_cse2()

◆ rest_of_handle_cse_after_global_opts()

◆ SAFE_HASH()

static unsigned SAFE_HASH ( rtx x,
machine_mode mode )
inlinestatic

◆ safe_hash()

static unsigned safe_hash ( rtx x,
machine_mode mode )
inlinestatic
Like canon_hash but with no side effects, i.e. do_not_record
and hash_arg_in_memory are not changed.   

References ggc_alloc(), hash_rtx(), table_elt::mode, and NULL.

Referenced by SAFE_HASH().

◆ set_live_p()

static bool set_live_p ( rtx set,
int * counts )
static
Return true if set is live.   

References is_dead_reg(), SET_DEST, set_noop_p(), SET_SRC, and side_effects_p().

Referenced by insn_live_p().

◆ try_back_substitute_reg()

static void try_back_substitute_reg ( rtx set,
rtx_insn * insn )
static
Special handling for (set REG0 REG1) where REG0 is the
"cheapest", cheaper than REG1.  After cse, REG1 will probably not
be used in the sequel, so (if easily done) change this insn to
(set REG1 REG0) and replace REG1 with REG0 in the previous insn
that computed their value.  Then REG1 will become a dead store
and won't cloud the situation for later optimizations.

Do not make this change if REG1 is a hard register, because it will
then be used in the sequel and we may be changing a two-operand insn
into a three-operand insn.

This is the last transformation that cse_insn will try to do.   

References apply_change_group(), BB_HEAD, BLOCK_FOR_INSN(), DEBUG_INSN_P, find_reg_note(), gcc_assert, GET_CODE, ggc_alloc(), HARD_REGISTER_P, NONJUMP_INSN_P, NOTE_P, NULL_RTX, PATTERN(), PREV_INSN(), qty_table, reg_mentioned_p(), REG_P, REG_QTY, REGNO, REGNO_QTY_VALID_P, remove_note(), rtx_equal_p(), SET, SET_DEST, SET_SRC, set_unique_reg_note(), validate_change(), and XEXP.

Referenced by cse_insn().

◆ try_const_anchors()

static rtx try_const_anchors ( rtx src_const,
machine_mode mode )
static
Try to express the constant SRC_CONST using a register+offset expression
derived from a constant anchor.  Return it if successful or NULL_RTX,
otherwise.   

References compute_const_anchors(), find_reg_offset_for_const(), GEN_INT, ggc_alloc(), HASH(), lookup(), table_elt::mode, NULL_RTX, and SCALAR_INT_MODE_P.

Referenced by cse_insn().

◆ use_related_value()

static rtx use_related_value ( rtx x,
struct table_elt * elt )
static
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.   

References table_elt::exp, table_elt::first_same_value, GET_CODE, get_integer_term(), GET_MODE, get_related_value(), ggc_alloc(), lookup(), table_elt::mode, table_elt::next_same_value, offset, plus_constant(), REG_P, table_elt::related_value, rtx_equal_p(), and SAFE_HASH().

Referenced by cse_insn().

◆ validate_canon_reg()

static void validate_canon_reg ( rtx * xloc,
rtx_insn * insn )
static
Subroutine of canon_reg.  Pass *XLOC through canon_reg, and validate
the result if necessary.  INSN is as for canon_reg.   

References canon_reg(), gcc_assert, ggc_alloc(), and validate_change().

Referenced by canon_reg().

Variable Documentation

◆ cse_cfg_altered

◆ cse_ebb_live_in

bitmap cse_ebb_live_in
static
Pointers to the live in/live out bitmaps for the boundaries of the
current EBB.   

Referenced by cse_extended_basic_block(), and make_regs_eqv().

◆ cse_ebb_live_out

bitmap cse_ebb_live_out
static

◆ cse_jumps_altered

bool cse_jumps_altered
static
True if CSE has altered conditional jump insns in such a way
that jump optimization should be redone.   

Referenced by cse_insn(), and cse_main().

◆ cse_reg_info_table

struct cse_reg_info* cse_reg_info_table
static
A table of cse_reg_info indexed by register numbers.   

Referenced by get_cse_reg_info(), get_cse_reg_info_1(), and init_cse_reg_info().

◆ cse_reg_info_table_first_uninitialized

unsigned int cse_reg_info_table_first_uninitialized
static
The index of the first entry that has not been initialized.   

Referenced by init_cse_reg_info().

◆ cse_reg_info_table_size

unsigned int cse_reg_info_table_size
static
The size of the above table.   

Referenced by init_cse_reg_info().

◆ cse_reg_info_timestamp

unsigned int cse_reg_info_timestamp
static
The timestamp at the beginning of the current run of
cse_extended_basic_block.  We increment this variable at the beginning of
the current run of cse_extended_basic_block.  The timestamp field of a
cse_reg_info entry matches the value of this variable if and only
if the entry has been initialized during the current run of
cse_extended_basic_block.   

Referenced by get_cse_reg_info(), get_cse_reg_info_1(), init_cse_reg_info(), and new_basic_block().

◆ cse_rtl_hooks

const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER
static

Referenced by cse_main().

◆ cse_visited_basic_blocks

sbitmap cse_visited_basic_blocks
static
A simple bitmap to track which basic blocks have been visited
already as part of an already processed extended basic block.   

Referenced by cse_extended_basic_block(), cse_find_path(), and cse_main().

◆ do_not_record

int do_not_record
static
canon_hash stores 1 in do_not_record if it notices a reference to PC or
some other volatile subexpression.   

Referenced by canon_hash(), cse_insn(), invariant_group_base_hasher::hash(), record_jump_cond(), and temp_slot_address_compute_hash().

◆ free_element_chain

struct table_elt* free_element_chain
static
Chain of `struct table_elt's made so far for this function
but currently removed from the table.   

Referenced by insert_with_costs(), new_basic_block(), and remove_from_table().

◆ hard_regs_in_table

HARD_REG_SET hard_regs_in_table
static
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.   

Referenced by insert_with_costs(), invalidate_for_call(), invalidate_reg(), and new_basic_block().

◆ hash_arg_in_memory

int hash_arg_in_memory
static
canon_hash stores 1 in hash_arg_in_memory
if it notices a reference to memory within the expression being hashed.   

Referenced by canon_hash(), cse_insn(), merge_equiv_classes(), and record_jump_cond().

◆ max_qty

int max_qty
static
Common subexpression elimination for GNU compiler.
   Copyright (C) 1987-2024 Free Software Foundation, Inc.

This file is part of GCC.

GCC 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 3, or (at your option) any later
version.

GCC 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 GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.   
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 in this code; so, at each label, we forget all
   that is known and start fresh.  This can be described as processing each
   extended basic block separately.  We have a separate pass to perform
   global CSE.

   Note CSE can turn a conditional or computed jump into a nop or
   an unconditional jump.  When this occurs we arrange to run the jump
   optimizer after CSE to delete the unreachable code.

   We use two data structures to record the equivalent expressions:
   a hash table for most expressions, and a vector of "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 (N)' records what quantity register N is currently thought
   of as containing.

   All real quantity numbers are greater than or equal to zero.
   If register N has not been assigned a quantity, `REG_QTY (N)' will
   equal -N - 1, which is always negative.

   Quantity numbers below zero do not exist and none of the `qty_table'
   entries should be referenced with a negative index.

   We also maintain a bidirectional chain of registers for each
   quantity number.  The `qty_table` members `first_reg' and `last_reg',
   and `reg_eqv_table' members `next' and `prev' 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_table `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 qty_table `const_rtx'.  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 qty_table
   `const_rtx'.

   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_table `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.

   `REG_TICK' and `REG_IN_TABLE', accessors for members of
   cse_reg_info, 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, `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.   
Length of qty_table vector.  We know in advance we will not need
a quantity number this big.   

Referenced by cse_extended_basic_block(), cse_main(), and make_new_qty().

◆ next_qty

int next_qty
static
Next quantity number to be allocated.
This is 1 + the largest number needed so far.   

Referenced by cse_extended_basic_block(), make_new_qty(), and new_basic_block().

◆ optimize_this_for_speed_p

bool optimize_this_for_speed_p
static

◆ qty_table

◆ recorded_label_ref

bool recorded_label_ref
static
True if we put a LABEL_REF into the hash table for an INSN
without a REG_LABEL_OPERAND, we have to rerun jump after CSE
to put in the note.   

Referenced by cse_extended_basic_block(), and cse_main().

◆ reg_eqv_table

struct reg_eqv_elem* reg_eqv_table
static
The table of all register equivalence chains.   

Referenced by cse_main(), delete_reg_equiv(), make_new_qty(), and make_regs_eqv().

◆ table

struct table_elt* table[HASH_SIZE]
static

Referenced by ipa_fn_summary::account_size_time(), add_mapping(), alloc_hash_table(), alloc_hash_table(), allocate_vn_table(), avail_exprs_stack::avail_exprs_stack(), compute_hash_table(), compute_hash_table(), compute_hash_table_work(), compute_hash_table_work(), compute_local_properties(), compute_local_properties(), hash_table< Descriptor, Lazy, Allocator >::create_ggc(), create_trace_edges(), decode_reg_name_and_count(), delete_insn(), delete_related_insns(), dump_hash_table(), dump_hash_table(), emit_jump_table_data(), equiv_class_lookup_or_add(), final_scan_insn_1(), find_AT_string_in_table(), find_bb_boundaries(), find_replaceable_exprs(), flush_hash_table(), force_nonfallthru_and_redirect(), free_hash_table(), free_hash_table(), free_vn_table(), get_initial_register_offset(), get_last_bb_insn(), gt_cleare_cache(), gt_ggc_mx(), handle_ignored_attributes_option(), hash_scan_insn(), hash_scan_insn(), hash_scan_set(), hash_scan_set(), include_pubname_in_output(), init_one_dwarf_reg_size(), insert_expr_in_table(), insert_set_in_table(), insert_with_costs(), instrument_decisions(), invalidate(), invalidate_for_call(), invalidate_memory(), invalidate_reg(), label_is_jump_target_p(), lookup(), lookup_for_remove(), lookup_page_table_entry(), lookup_set(), lto_input_mode_table(), make_edges(), maybe_reset_location_view(), merge_blocks_move_successor_nojumps(), new_basic_block(), output_line_info(), output_one_line_info_table(), patch_jump_insn(), purge_dead_tablejump_edges(), rehash_using_reg(), remove_from_table(), remove_invalid_refs(), remove_invalid_subreg_refs(), rtl_tidy_fallthru_edge(), safe_lookup_page_table_entry(), set_eh_throw_stmt_table(), set_page_table_entry(), shorten_branches(), tablejump_p(), try_redirect_by_replacing_jump(), and vn_nary_op_insert_into().

◆ this_insn

rtx_insn* this_insn
static