Add cselib; use it in loop and reload_cse_regs

From-SVN: r32538
This commit is contained in:
Bernd Schmidt 2000-03-14 18:36:18 +00:00 committed by Bernd Schmidt
parent 4bdf01f210
commit eab5c70a03
10 changed files with 1655 additions and 778 deletions

View File

@ -1,3 +1,67 @@
2000-03-14 Bernd Schmidt <bernds@cygnus.co.uk>
* cselib.h: New file.
* alias.c: Include "cselib.h".
(fixed_scalar_and_varying_struct_p): Accept the addresses of the
MEMs as two new arguments.
(get_addr): New static function.
(find_base_term): Handle VALUEs.
(memrefs_conflict_p): Likewise.
(true_dependence): Call get_addr on the addresses.
Call fixed_scalar_and_varying_struct_p with addresses that have been
passed through get_addr and canon_rtx.
(write_dependence_p): Move DIFFERENT_ALIAS_SETS_P test for consistency
with true_dependence.
Call get_addr on the addresses; don't call canon_rtx on the MEMs.
* loop.c: Include "cselib.h".
(load_mems): Process extended basic block that enters the loop with
cselib. Use that information to change initialization of the shadow
register so that a constant equivalence is seen by later passes.
* reload1.c: Include "cselib.h".
(reload_cse_invalidate_regno): Delete function.
(reload_cse_mem_conflict_p): Likewise.
(reload_cse_invalidate_mem): Likewise.
(reload_cse_invalidate_rtx): Likewise.
(reload_cse_regno_equal_p): Likewise.
(reload_cse_check_clobber): Likewise.
(reload_cse_record_set): Likewise.
(reg_values): Delete static variable.
(invalidate_regno_rtx): Likewise.
(reload_cse_delete_noop_set): New static function.
(reload_cse_simplify): New static function, broken out of
reload_cse_regs_1.
(reload_cse_noop_set_p): Delete unused argument INSN.
Just call rtx_equal_for_cselib_p on set source and destination.
(reload_cse_regs_1): Break out some code into reload_cse_simplify and
reload_cse_delete_noop_set. Delete code to keep track of values; use
cselib functions instead. Delete code to push/pop obstacks.
(reload_cse_simplify_set): Use cselib to find equivalent values.
Delete code to push/pop obstacks.
(reload_cse_simplify_operands): Likewise.
* rtl.def (VALUE): New rtx code.
* rtl.h (union rtunion_def): New elt rt_cselib.
(X0CSELIB, CSELIB_VAL_PTR): New macros.
* simplify_rtx.c: Include "ggc.h", "obstack.h", "cselib.h".
(new_elt_list, new_elt_loc_list, unchain_one_value, clear_table,
unchain_one_elt_list, unchain_one_elt_loc_list, check_useless_values,
discard_useless_locs, discard_useless_values, entry_and_rtx_equal_p,
hash_rtx, new_cselib_val, add_mem_for_addr, get_value_hash,
cselib_lookup_mem, cselib_subst_to_values, cselib_invalidate_regno,
cselib_mem_conflict_p, cselib_invalidate_mem, cselib_invalidate_rtx,
cselib_record_set, cselib_record_sets): New static functions.
(cselib_lookup, cselib_update_varray_sizes, cselib_init,
cselib_finish, cselib_process_insn, rtx_equal_for_cselib_p,
references_value_p): New functions.
(MAX_USELESS_VALUES, REG_VALUES): New macros.
(table, cselib_current_insn, next_unknown_value, cselib_nregs,
n_useless_values, reg_values, callmem, cselib_obstack,
cselib_startobj, empty_vals, empty_elt_lists, empty_elt_loc_lists):
New static variables.
* varray.h (union varray_data_tag): New elt te.
(VARRAY_ELT_LIST_INIT, VARRAY_ELT_LIST): New macros.
* Makefile.in (reload1.o, loop.o, simplify-rtx.o, alias.o): Update
dependencies.
2000-03-14 Nick Clifton <nickc@cygnus.com>
* gcc.c (do_spec_1): Catch the case where %* is used in a

View File

@ -1556,7 +1556,7 @@ jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \
simplify-rtx.o : simplify-rtx.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
output.h function.h
output.h function.h cselib.h ggc.h $(srcdir)/../include/obstack.h
cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h function.h ggc.h
gcse.o : gcse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \
@ -1574,7 +1574,7 @@ profile.o : profile.c $(CONFIG_H) system.h $(RTL_H) flags.h insn-flags.h \
ggc.h
loop.o : loop.c $(CONFIG_H) system.h $(RTL_H) flags.h $(LOOP_H) insn-config.h \
insn-flags.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) real.h \
$(BASIC_BLOCK_H) function.h toplev.h varray.h except.h
$(BASIC_BLOCK_H) function.h toplev.h varray.h except.h cselib.h
unroll.o : unroll.c $(CONFIG_H) system.h $(RTL_H) insn-config.h function.h \
$(INTEGRATE_H) $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) $(LOOP_H) toplev.h \
varray.h
@ -1600,7 +1600,7 @@ reload.o : reload.c $(CONFIG_H) system.h $(RTL_H) flags.h output.h $(EXPR_H) \
function.h real.h toplev.h
reload1.o : reload1.c $(CONFIG_H) system.h $(RTL_H) real.h flags.h $(EXPR_H) \
reload.h $(REGS_H) hard-reg-set.h insn-config.h insn-flags.h insn-codes.h \
$(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h
$(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h cselib.h
caller-save.o : caller-save.c $(CONFIG_H) system.h $(RTL_H) flags.h \
$(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) function.h \
$(RECOG_H) reload.h $(EXPR_H) toplev.h
@ -1608,7 +1608,8 @@ reorg.o : reorg.c $(CONFIG_H) system.h $(RTL_H) conditions.h hard-reg-set.h \
$(BASIC_BLOCK_H) $(REGS_H) insn-config.h insn-attr.h insn-flags.h \
$(RECOG_H) function.h flags.h output.h $(EXPR_H) toplev.h
alias.o : alias.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h \
$(REGS_H) toplev.h output.h $(EXPR_H) insn-flags.h ggc.h function.h
$(REGS_H) toplev.h output.h $(EXPR_H) insn-flags.h ggc.h function.h \
cselib.h
regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \
$(RECOG_H) output.h reload.h $(REGS_H) hard-reg-set.h flags.h function.h \
$(EXPR_H) insn-flags.h $(BASIC_BLOCK_H) toplev.h

View File

@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "cselib.h"
#include "splay-tree.h"
#include "ggc.h"
@ -81,6 +82,7 @@ typedef struct alias_set_entry
static rtx canon_rtx PARAMS ((rtx));
static int rtx_equal_for_memref_p PARAMS ((rtx, rtx));
static rtx find_symbolic_term PARAMS ((rtx));
static rtx get_addr PARAMS ((rtx));
static int memrefs_conflict_p PARAMS ((int, rtx, int, rtx,
HOST_WIDE_INT));
static void record_set PARAMS ((rtx, rtx, void *));
@ -91,7 +93,8 @@ static rtx find_base_value PARAMS ((rtx));
static int mems_in_disjoint_alias_sets_p PARAMS ((rtx, rtx));
static int insert_subset_children PARAMS ((splay_tree_node, void*));
static alias_set_entry get_alias_set_entry PARAMS ((int));
static rtx fixed_scalar_and_varying_struct_p PARAMS ((rtx, rtx, int (*)(rtx)));
static rtx fixed_scalar_and_varying_struct_p PARAMS ((rtx, rtx, rtx, rtx,
int (*)(rtx)));
static int aliases_everything_p PARAMS ((rtx));
static int write_dependence_p PARAMS ((rtx, rtx, int));
static int nonlocal_reference_p PARAMS ((rtx));
@ -737,6 +740,9 @@ static rtx
find_base_term (x)
register rtx x;
{
cselib_val *val;
struct elt_loc_list *l;
switch (GET_CODE (x))
{
case REG:
@ -751,6 +757,13 @@ find_base_term (x)
case POST_DEC:
return find_base_term (XEXP (x, 0));
case VALUE:
val = CSELIB_VAL_PTR (x);
for (l = val->locs; l; l = l->next)
if ((x = find_base_term (l->loc)) != 0)
return x;
return 0;
case CONST:
x = XEXP (x, 0);
if (GET_CODE (x) != PLUS && GET_CODE (x) != MINUS)
@ -905,6 +918,30 @@ base_alias_check (x, y, x_mode, y_mode)
return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode);
}
/* Convert the address X into something we can use. This is done by returning
it unchanged unless it is a value; in the latter case we call cselib to get
a more useful rtx. */
static rtx
get_addr (x)
rtx x;
{
cselib_val *v;
struct elt_loc_list *l;
if (GET_CODE (x) != VALUE)
return x;
v = CSELIB_VAL_PTR (x);
for (l = v->locs; l; l = l->next)
if (CONSTANT_P (l->loc))
return l->loc;
for (l = v->locs; l; l = l->next)
if (GET_CODE (l->loc) != REG && GET_CODE (l->loc) != MEM)
return l->loc;
if (v->locs)
return v->locs->loc;
return x;
}
/* Return the address of the (N_REFS + 1)th memory reference to ADDR
where SIZE is the size in bytes of the memory reference. If ADDR
is not modified by the memory reference then ADDR is returned. */
@ -961,13 +998,16 @@ addr_side_effect_eval (addr, size, n_refs)
Nice to notice that varying addresses cannot conflict with fp if no
local variables had their addresses taken, but that's too hard now. */
static int
memrefs_conflict_p (xsize, x, ysize, y, c)
register rtx x, y;
int xsize, ysize;
HOST_WIDE_INT c;
{
if (GET_CODE (x) == VALUE)
x = get_addr (x);
if (GET_CODE (y) == VALUE)
y = get_addr (y);
if (GET_CODE (x) == HIGH)
x = XEXP (x, 0);
else if (GET_CODE (x) == LO_SUM)
@ -1185,17 +1225,15 @@ read_dependence (mem, x)
MEM2 if vice versa. Otherwise, returns NULL_RTX. If a non-NULL
value is returned MEM1 and MEM2 can never alias. VARIES_P is used
to decide whether or not an address may vary; it should return
nonzero whenever variation is possible. */
static rtx
fixed_scalar_and_varying_struct_p (mem1, mem2, varies_p)
rtx mem1;
rtx mem2;
int (*varies_p) PARAMS ((rtx));
{
rtx mem1_addr = XEXP (mem1, 0);
rtx mem2_addr = XEXP (mem2, 0);
nonzero whenever variation is possible.
MEM1_ADDR and MEM2_ADDR are the addresses of MEM1 and MEM2. */
static rtx
fixed_scalar_and_varying_struct_p (mem1, mem2, mem1_addr, mem2_addr, varies_p)
rtx mem1, mem2;
rtx mem1_addr, mem2_addr;
int (*varies_p) PARAMS ((rtx));
{
if (MEM_SCALAR_P (mem1) && MEM_IN_STRUCT_P (mem2)
&& !varies_p (mem1_addr) && varies_p (mem2_addr))
/* MEM1 is a scalar at a fixed address; MEM2 is a struct at a
@ -1260,11 +1298,14 @@ true_dependence (mem, mem_mode, x, varies)
if (mem_mode == VOIDmode)
mem_mode = GET_MODE (mem);
if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x), mem_mode))
x_addr = get_addr (XEXP (x, 0));
mem_addr = get_addr (XEXP (mem, 0));
if (! base_alias_check (x_addr, mem_addr, GET_MODE (x), mem_mode))
return 0;
x_addr = canon_rtx (XEXP (x, 0));
mem_addr = canon_rtx (XEXP (mem, 0));
x_addr = canon_rtx (x_addr);
mem_addr = canon_rtx (mem_addr);
if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
SIZE_FOR_MODE (x), x_addr, 0))
@ -1283,7 +1324,8 @@ true_dependence (mem, mem_mode, x, varies)
if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
return 1;
return !fixed_scalar_and_varying_struct_p (mem, x, varies);
return ! fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
varies);
}
/* Returns non-zero if a write to X might alias a previous read from
@ -1301,32 +1343,33 @@ write_dependence_p (mem, x, writep)
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
/* If MEM is an unchanging read, then it can't possibly conflict with
the store to X, because there is at most one store to MEM, and it must
have occurred somewhere before MEM. */
if (!writep && RTX_UNCHANGING_P (mem))
return 0;
if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x),
x_addr = get_addr (XEXP (x, 0));
mem_addr = get_addr (XEXP (mem, 0));
if (! base_alias_check (x_addr, mem_addr, GET_MODE (x),
GET_MODE (mem)))
return 0;
x = canon_rtx (x);
mem = canon_rtx (mem);
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
x_addr = XEXP (x, 0);
mem_addr = XEXP (mem, 0);
x_addr = canon_rtx (x_addr);
mem_addr = canon_rtx (mem_addr);
if (!memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
SIZE_FOR_MODE (x), x_addr, 0))
return 0;
fixed_scalar
= fixed_scalar_and_varying_struct_p (mem, x, rtx_addr_varies_p);
= fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
rtx_addr_varies_p);
return (!(fixed_scalar == mem && !aliases_everything_p (x))
&& !(fixed_scalar == x && !aliases_everything_p (mem)));
}

66
gcc/cselib.h Normal file
View File

@ -0,0 +1,66 @@
/* Common subexpression elimination for GNU compiler.
Copyright (C) 1987, 88, 89, 92-7, 1998, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Describe a value. */
typedef struct cselib_val_struct
{
/* The hash value. */
unsigned int value;
union
{
/* A VALUE rtx that points back to this structure. */
rtx val_rtx;
/* Used to keep a list of free cselib_val structures. */
struct cselib_val_struct *next_free;
} u;
/* All rtl expressions that hold this value at the current time during a
scan. */
struct elt_loc_list *locs;
/* If this value is used as an address, points to a list of values that
use it as an address in a MEM. */
struct elt_list *addr_list;
} cselib_val;
/* A list of rtl expressions that hold the same value. */
struct elt_loc_list
{
/* Next element in the list. */
struct elt_loc_list *next;
/* An rtl expression that holds the value. */
rtx loc;
/* The insn that made the equivalence. */
rtx setting_insn;
};
/* A list of cselib_val structures. */
struct elt_list
{
struct elt_list *next;
cselib_val *elt;
};
extern cselib_val *cselib_lookup PARAMS ((rtx, enum machine_mode, int));
extern void cselib_update_varray_sizes PARAMS ((void));
extern void cselib_init PARAMS ((void));
extern void cselib_finish PARAMS ((void));
extern void cselib_process_insn PARAMS ((rtx));
extern int rtx_equal_for_cselib_p PARAMS ((rtx, rtx));
extern int references_value_p PARAMS ((rtx, int));

View File

@ -51,6 +51,7 @@ Boston, MA 02111-1307, USA. */
#include "flags.h"
#include "real.h"
#include "loop.h"
#include "cselib.h"
#include "except.h"
#include "toplev.h"
@ -9773,6 +9774,19 @@ load_mems (loop)
if (loop_mems_idx == 0)
return;
/* Find start of the extended basic block that enters the loop. */
for (p = loop->start;
PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
p = PREV_INSN (p))
;
cselib_init ();
/* Build table of mems that get set to constant values before the
loop. */
for (; p != loop->start; p = NEXT_INSN (p))
cselib_process_insn (p);
/* Check to see if it's possible that some instructions in the
loop are never executed. */
for (p = next_insn_in_loop (loop, loop->scan_start);
@ -9924,13 +9938,49 @@ load_mems (loop)
loop_mems[i].optimize = 0;
else
{
int j;
rtx set;
/* Load the memory immediately before LOOP->START, which is
the NOTE_LOOP_BEG. */
set = gen_move_insn (reg, mem);
emit_insn_before (set, loop->start);
cselib_val *e = cselib_lookup (mem, VOIDmode, 0);
rtx set;
rtx best = mem;
int j;
struct elt_loc_list *const_equiv = 0;
if (e)
{
struct elt_loc_list *equiv;
struct elt_loc_list *best_equiv = 0;
for (equiv = e->locs; equiv; equiv = equiv->next)
{
if (CONSTANT_P (equiv->loc))
const_equiv = equiv;
else if (GET_CODE (equiv->loc) == REG)
best_equiv = equiv;
}
/* Use the constant equivalence if that is cheap enough. */
if (! best_equiv)
best_equiv = const_equiv;
else if (const_equiv
&& (rtx_cost (const_equiv->loc, SET)
<= rtx_cost (best_equiv->loc, SET)))
{
best_equiv = const_equiv;
const_equiv = 0;
}
/* If best_equiv is nonzero, we know that MEM is set to a
constant or register before the loop. We will use this
knowledge to initialize the shadow register with that
constant or reg rather than by loading from MEM. */
if (best_equiv)
best = copy_rtx (best_equiv->loc);
}
set = gen_move_insn (reg, best);
set = emit_insn_before (set, loop->start);
if (const_equiv)
REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
copy_rtx (const_equiv->loc),
REG_NOTES (set));
if (written)
{
@ -9992,6 +10042,8 @@ load_mems (loop)
JUMP_LABEL (p) = label;
}
}
cselib_finish ();
}
/* For communication between note_reg_stored and its caller. */

File diff suppressed because it is too large Load Diff

View File

@ -530,6 +530,9 @@ DEF_RTL_EXPR(CONST, "const", "e", 'o')
by a SET whose first operand is (PC). */
DEF_RTL_EXPR(PC, "pc", "", 'o')
/* Used in the cselib routines to describe a value. */
DEF_RTL_EXPR(VALUE, "value", "0", 'o')
/* A register. The "operand" is the register number, accessed with
the REGNO macro. If this number is less than FIRST_PSEUDO_REGISTER
than a hardware register is being referred to. The second operand

View File

@ -92,6 +92,7 @@ typedef union rtunion_def
struct rtvec_def *rtvec;
enum machine_mode rttype;
addr_diff_vec_flags rt_addr_diff_vec_flags;
struct cselib_val_struct *rt_cselib;
struct bitmap_head_def *rtbit;
union tree_node *rttree;
struct basic_block_def *bb;
@ -330,6 +331,7 @@ extern void rtvec_check_failed_bounds PARAMS ((rtvec, int,
#define X0TREE(RTX, N) (RTL_CHECK1(RTX, N, '0').rttree)
#define X0BBDEF(RTX, N) (RTL_CHECK1(RTX, N, '0').bb)
#define X0ADVFLAGS(RTX, N) (RTL_CHECK1(RTX, N, '0').rt_addr_diff_vec_flags)
#define X0CSELIB(RTX, N) (RTL_CHECK1(RTX, N, '0').rt_cselib)
#define XCWINT(RTX, N, C) (RTL_CHECKC1(RTX, N, C).rtwint)
#define XCINT(RTX, N, C) (RTL_CHECKC1(RTX, N, C).rtint)
@ -341,6 +343,7 @@ extern void rtvec_check_failed_bounds PARAMS ((rtvec, int,
#define XCTREE(RTX, N, C) (RTL_CHECKC1(RTX, N, C).rttree)
#define XCBBDEF(RTX, N, C) (RTL_CHECKC1(RTX, N, C).bb)
#define XCADVFLAGS(RTX, N, C) (RTL_CHECKC1(RTX, N, C).rt_addr_diff_vec_flags)
#define XCCSELIB(RTX, N, C) (RTL_CHECKC1(RTX, N, C).rt_cselib)
#define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M)
#define XCVECLEN(RTX, N, C) GET_NUM_ELEM (XCVEC (RTX, N, C))
@ -470,6 +473,8 @@ extern void rtvec_check_failed_bounds PARAMS ((rtvec, int,
#define ADDR_DIFF_VEC_FLAGS(RTX) X0ADVFLAGS(RTX, 4)
#define CSELIB_VAL_PTR(RTX) X0CSELIB(RTX, 0)
/* Don't forget to change reg_note_name in rtl.c. */
enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4,
REG_EQUAL = 5, REG_RETVAL = 6, REG_LIBCALL = 7,

File diff suppressed because it is too large Load Diff

View File

@ -76,6 +76,7 @@ typedef union varray_data_tag {
struct reg_info_def *reg[1];
struct const_equiv_data const_equiv[1];
struct basic_block_def *bb[1];
struct elt_list *te[1];
} varray_data;
/* Virtual array of pointers header. */
@ -152,6 +153,9 @@ extern varray_type varray_init PARAMS ((size_t, size_t, const char *));
#define VARRAY_BB_INIT(va, num, name) \
va = varray_init (num, sizeof (struct basic_block_def *), name)
#define VARRAY_ELT_LIST_INIT(va, num, name) \
va = varray_init (num, sizeof (struct elt_list *), name)
/* Free up memory allocated by the virtual array, but do not free any of the
elements involved. */
#define VARRAY_FREE(vp) \
@ -219,6 +223,7 @@ extern void varray_check_failed PARAMS ((varray_type, size_t,
#define VARRAY_REG(VA, N) VARRAY_CHECK (VA, N, reg)
#define VARRAY_CONST_EQUIV(VA, N) VARRAY_CHECK (VA, N, const_equiv)
#define VARRAY_BB(VA, N) VARRAY_CHECK (VA, N, bb)
#define VARRAY_ELT_LIST(VA, N) VARRAY_CHECK (VA, N, te)
/* Push a new element on the end of VA, extending it if necessary. */
#define VARRAY_PUSH_CHAR(VA, X) VARRAY_PUSH (VA, c, X)