Copy propagation for hoisted mems in loop.c.
From-SVN: r30638
This commit is contained in:
parent
429d7c746f
commit
c29f60c03c
|
@ -1,3 +1,11 @@
|
|||
1999-11-23 Bernd Schmidt <bernds@cygnus.co.uk>
|
||||
|
||||
* loop.c: Include "basic-block.h".
|
||||
(try_copy_prop, replace_loop_reg): New functions.
|
||||
(load_mems): Detect registers that just hold copies of the hoisted
|
||||
mem, and call try_copy_prop to eliminate them.
|
||||
* Makefile.in (loop.o): Update dependencies.
|
||||
|
||||
Tue Nov 23 01:03:29 1999 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
* Makefile.in (gencheck.o): Depend on gencheck.h.
|
||||
|
|
|
@ -1551,7 +1551,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 \
|
||||
function.h toplev.h varray.h except.h
|
||||
$(BASIC_BLOCK_H) function.h toplev.h varray.h except.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
|
||||
flow.o : flow.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h insn-config.h \
|
||||
|
|
114
gcc/loop.c
114
gcc/loop.c
|
@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "obstack.h"
|
||||
#include "function.h"
|
||||
#include "expr.h"
|
||||
#include "basic-block.h"
|
||||
#include "insn-config.h"
|
||||
#include "insn-flags.h"
|
||||
#include "regs.h"
|
||||
|
@ -337,6 +338,8 @@ static void load_mems_and_recount_loop_regs_set PROTO((rtx, rtx, rtx,
|
|||
static void load_mems PROTO((rtx, rtx, rtx, rtx));
|
||||
static int insert_loop_mem PROTO((rtx *, void *));
|
||||
static int replace_loop_mem PROTO((rtx *, void *));
|
||||
static int replace_loop_reg PROTO((rtx *, void *));
|
||||
static void try_copy_prop PROTO((rtx, rtx, rtx, rtx, int));
|
||||
static int replace_label PROTO((rtx *, void *));
|
||||
|
||||
typedef struct rtx_and_int {
|
||||
|
@ -9717,6 +9720,7 @@ load_mems (scan_start, end, loop_top, start)
|
|||
rtx end_label = NULL_RTX;
|
||||
/* Nonzero if the next instruction may never be executed. */
|
||||
int next_maybe_never = 0;
|
||||
int last_max_reg = max_reg_num ();
|
||||
|
||||
if (loop_mems_idx == 0)
|
||||
return;
|
||||
|
@ -9756,6 +9760,7 @@ load_mems (scan_start, end, loop_top, start)
|
|||
/* Actually move the MEMs. */
|
||||
for (i = 0; i < loop_mems_idx; ++i)
|
||||
{
|
||||
regset_head copies;
|
||||
int written = 0;
|
||||
rtx reg;
|
||||
rtx mem = loop_mems[i].mem;
|
||||
|
@ -9817,6 +9822,8 @@ load_mems (scan_start, end, loop_top, start)
|
|||
loop, but later discovered that we could not. */
|
||||
continue;
|
||||
|
||||
INIT_REG_SET (&copies);
|
||||
|
||||
/* Allocate a pseudo for this MEM. We set REG_USERVAR_P in
|
||||
order to keep scan_loop from moving stores to this MEM
|
||||
out of the loop just because this REG is neither a
|
||||
|
@ -9827,14 +9834,37 @@ load_mems (scan_start, end, loop_top, start)
|
|||
|
||||
/* Now, replace all references to the MEM with the
|
||||
corresponding pesudos. */
|
||||
maybe_never = 0;
|
||||
for (p = next_insn_in_loop (scan_start, scan_start, end, loop_top);
|
||||
p != NULL_RTX;
|
||||
p = next_insn_in_loop (p, scan_start, end, loop_top))
|
||||
{
|
||||
rtx_and_int ri;
|
||||
ri.r = p;
|
||||
ri.i = i;
|
||||
for_each_rtx (&p, replace_loop_mem, &ri);
|
||||
rtx set;
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
|
||||
{
|
||||
/* See if this copies the mem into a register that isn't
|
||||
modified afterwards. We'll try to do copy propagation
|
||||
a little further on. */
|
||||
set = single_set (p);
|
||||
if (set
|
||||
/* @@@ This test is _way_ too conservative. */
|
||||
&& ! maybe_never
|
||||
&& GET_CODE (SET_DEST (set)) == REG
|
||||
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
|
||||
&& REGNO (SET_DEST (set)) < last_max_reg
|
||||
&& VARRAY_INT (n_times_set, REGNO (SET_DEST (set))) == 1
|
||||
&& rtx_equal_p (SET_SRC (set), loop_mems[i].mem))
|
||||
SET_REGNO_REG_SET (&copies, REGNO (SET_DEST (set)));
|
||||
ri.r = p;
|
||||
ri.i = i;
|
||||
for_each_rtx (&p, replace_loop_mem, &ri);
|
||||
}
|
||||
|
||||
if (GET_CODE (p) == CODE_LABEL
|
||||
|| GET_CODE (p) == JUMP_INSN)
|
||||
maybe_never = 1;
|
||||
}
|
||||
|
||||
if (! apply_change_group ())
|
||||
|
@ -9842,6 +9872,7 @@ load_mems (scan_start, end, loop_top, start)
|
|||
loop_mems[i].optimize = 0;
|
||||
else
|
||||
{
|
||||
int j;
|
||||
rtx set;
|
||||
|
||||
/* Load the memory immediately before START, which is
|
||||
|
@ -9874,6 +9905,16 @@ load_mems (scan_start, end, loop_top, start)
|
|||
print_rtl (loop_dump_stream, mem);
|
||||
fputc ('\n', loop_dump_stream);
|
||||
}
|
||||
|
||||
/* Attempt a bit of copy propagation. This helps untangle the
|
||||
data flow, and enables {basic,general}_induction_var to find
|
||||
more bivs/givs. */
|
||||
EXECUTE_IF_SET_IN_REG_SET
|
||||
(&copies, FIRST_PSEUDO_REGISTER, j,
|
||||
{
|
||||
try_copy_prop (scan_start, loop_top, end, loop_mems[i].reg, j);
|
||||
});
|
||||
CLEAR_REG_SET (&copies);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9901,6 +9942,51 @@ load_mems (scan_start, end, loop_top, start)
|
|||
}
|
||||
}
|
||||
|
||||
/* Try to replace every occurrence of pseudo REGNO with REPLACEMENT.
|
||||
There must be exactly one insn that sets this pseudo; it will be
|
||||
deleted if all replacements succeed and we can prove that the register
|
||||
is not used after the loop.
|
||||
The arguments SCAN_START, LOOP_TOP and END are as in load_mems. */
|
||||
static void
|
||||
try_copy_prop (scan_start, loop_top, end, replacement, regno)
|
||||
rtx scan_start, loop_top, end, replacement;
|
||||
int regno;
|
||||
{
|
||||
rtx init_insn = 0;
|
||||
rtx insn;
|
||||
for (insn = next_insn_in_loop (scan_start, scan_start, end, loop_top);
|
||||
insn != NULL_RTX;
|
||||
insn = next_insn_in_loop (insn, scan_start, end, loop_top))
|
||||
{
|
||||
rtx set;
|
||||
rtx array[3] = { regno_reg_rtx[regno], replacement, insn };
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
|
||||
continue;
|
||||
set = single_set (insn);
|
||||
if (set
|
||||
&& GET_CODE (SET_DEST (set)) == REG
|
||||
&& REGNO (SET_DEST (set)) == regno)
|
||||
{
|
||||
if (init_insn)
|
||||
abort ();
|
||||
init_insn = insn;
|
||||
}
|
||||
for_each_rtx (&insn, replace_loop_reg, array);
|
||||
}
|
||||
if (! init_insn)
|
||||
abort ();
|
||||
if (apply_change_group ())
|
||||
{
|
||||
if (uid_luid[REGNO_LAST_UID (regno)] < INSN_LUID (end))
|
||||
{
|
||||
PUT_CODE (init_insn, NOTE);
|
||||
NOTE_LINE_NUMBER (init_insn) = NOTE_INSN_DELETED;
|
||||
}
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream, " Replaced reg %d.\n", regno);
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace MEM with its associated pseudo register. This function is
|
||||
called from load_mems via for_each_rtx. DATA is actually an
|
||||
rtx_and_int * describing the instruction currently being scanned
|
||||
|
@ -9949,6 +10035,28 @@ replace_loop_mem (mem, data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Replace one register with another. Called through for_each_rtx; PX points
|
||||
to the rtx being scanned. DATA is actually an array of three rtx's; the
|
||||
first one is the one to be replaced, and the second one the replacement.
|
||||
The third one is the current insn. */
|
||||
|
||||
static int
|
||||
replace_loop_reg (px, data)
|
||||
rtx *px;
|
||||
void *data;
|
||||
{
|
||||
rtx x = *px;
|
||||
rtx *array = (rtx *)data;
|
||||
|
||||
if (x == NULL_RTX)
|
||||
return 0;
|
||||
|
||||
if (x == array[0])
|
||||
validate_change (array[2], px, array[1], 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Replace occurrences of the old exit label for the loop with the new
|
||||
one. DATA is an rtx_pair containing the old and new labels,
|
||||
respectively. */
|
||||
|
|
Loading…
Reference in New Issue