5139 lines
150 KiB
C
5139 lines
150 KiB
C
/* Move constant computations out of loops.
|
||
Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
|
||
|
||
This file is part of GNU CC.
|
||
|
||
GNU CC is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 1, or (at your option)
|
||
any later version.
|
||
|
||
GNU CC is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
|
||
/* This is the loop optimization pass of the compiler.
|
||
It finds invariant computations within loops and moves them
|
||
to the beginning of the loop. Then it identifies basic and
|
||
general induction variables. Strength reduction is applied to the general
|
||
induction variables, and induction variable elimination is applied to
|
||
the basic induction variables.
|
||
|
||
It also finds cases where
|
||
a register is set within the loop by zero-extending a narrower value
|
||
and changes these to zero the entire register once before the loop
|
||
and merely copy the low part within the loop.
|
||
|
||
Most of the complexity is in heuristics to decide when it is worth
|
||
while to do these things. */
|
||
|
||
/* ??? verify_loop would run faster if we made one table
|
||
of the minimum and maximum luids from which each label is reached.
|
||
Also, it would be faster if loop_store_addrs were a hash table. */
|
||
|
||
#include "config.h"
|
||
#include "rtl.h"
|
||
#include "expr.h"
|
||
#include "insn-config.h"
|
||
#include "regs.h"
|
||
#include "hard-reg-set.h"
|
||
#include "recog.h"
|
||
#include "flags.h"
|
||
#include <stdio.h>
|
||
|
||
/* Vector mapping INSN_UIDs to luids.
|
||
The luids are like uids but increase monononically always.
|
||
We use them to see whether a jump comes from outside a given loop. */
|
||
|
||
static short *uid_luid;
|
||
|
||
/* Get the luid of an insn. */
|
||
|
||
#define INSN_LUID(INSN) (uid_luid[INSN_UID (INSN)])
|
||
|
||
/* 1 + largest uid of any insn. */
|
||
|
||
static int max_uid;
|
||
|
||
/* 1 + luid of last insn. */
|
||
|
||
static int max_luid;
|
||
|
||
/* Nonzero if somewhere in the current loop
|
||
there is either a subroutine call,
|
||
or a store into a memory address that is not fixed,
|
||
or a store in a BLKmode memory operand,
|
||
or too many different fixed addresses stored in
|
||
to record them all in `loop_store_addrs'.
|
||
|
||
In any of these cases, no memory location can be regarded
|
||
as invariant. */
|
||
|
||
static int unknown_address_altered;
|
||
|
||
/* Nonzero if somewhere in the current loop there is a store
|
||
into a memory address that is not fixed but is known to be
|
||
part of an aggregate.
|
||
|
||
In this case, no memory reference in an aggregate may be
|
||
considered invariant. */
|
||
|
||
static int unknown_aggregate_altered;
|
||
|
||
/* Nonzero if somewhere in the current loop there is a store
|
||
into a memory address other than a fixed address not in an aggregate.
|
||
|
||
In this case, no memory reference in an aggregate at a varying address
|
||
may be considered invariant. */
|
||
|
||
static int fixed_aggregate_altered;
|
||
|
||
/* Nonzero if there is a subroutine call in the current loop.
|
||
(unknown_address_altered is also nonzero in this case.) */
|
||
|
||
static int loop_has_call;
|
||
|
||
/* Added loop_continue which is the NOTE_INSN_LOOP_CONT of the
|
||
current loop. A continue statement will generate a branch to
|
||
NEXT_INSN (loop_continue). */
|
||
|
||
static rtx loop_continue;
|
||
|
||
/* Indexed by register number, contains the number of times the reg
|
||
is set during the loop being scanned.
|
||
During code motion, -1 indicates a reg that has been made a candidate.
|
||
After code motion, regs moved have 0 (which is accurate now)
|
||
while the failed candidates have the original number of times set.
|
||
|
||
Therefore, at all times, 0 indicates an invariant register;
|
||
-1 a conditionally invariant one. */
|
||
|
||
static short *n_times_set;
|
||
|
||
/* Original value of n_times_set; same except that this value
|
||
is not set to -1 for a reg whose sets have been made candidates
|
||
and not set to 0 for a reg that is moved. */
|
||
|
||
static short *n_times_used;
|
||
|
||
/* Nonzero means reg N has already been moved out of one loop.
|
||
This reduces the desire to move it out of another. */
|
||
|
||
static char *moved_once;
|
||
|
||
/* Array of fixed memory addresses that are stored in this loop.
|
||
If there are too many to fit here,
|
||
we just turn on unknown_address_altered. */
|
||
|
||
#define NUM_STORES 10
|
||
static rtx loop_store_addrs[NUM_STORES];
|
||
static int loop_store_widths[NUM_STORES];
|
||
|
||
/* Index of first available slot in above array. */
|
||
static int loop_store_addrs_idx;
|
||
|
||
/* Count of movable (i.e. invariant) instructions discovered in the loop. */
|
||
static int num_movables;
|
||
|
||
/* Count of memory write instructions discovered in the loop. */
|
||
static int num_mem_sets;
|
||
|
||
/* Number of loops contained within the current one, including itself. */
|
||
static int loops_enclosed;
|
||
|
||
/* Bound on pseudo register number before loop optimization.
|
||
A pseudo has valid regscan info if its number is < old_max_reg. */
|
||
static int old_max_reg;
|
||
|
||
/* During the analysis of a loop, a chain of `struct movable's
|
||
is made to record all the movable insns found.
|
||
Then the entire chain can be scanned to decide which to move. */
|
||
|
||
struct movable
|
||
{
|
||
rtx insn; /* A movable insn */
|
||
rtx set_src; /* The expression this reg is set from.
|
||
Either SET_SRC (body) or a REG_EQUAL. */
|
||
int consec; /* Number of consecutive following insns
|
||
that must be moved with this one. */
|
||
int regno; /* The register it sets */
|
||
short lifetime; /* lifetime of that register;
|
||
may be adjusted when matching movables
|
||
that load the same value are found. */
|
||
short savings; /* Number of insns we can move for this reg,
|
||
including other movables that force this
|
||
or match this one. */
|
||
unsigned int cond : 1; /* 1 if only conditionally movable */
|
||
unsigned int force : 1; /* 1 means MUST move this insn */
|
||
unsigned int global : 1; /* 1 means reg is live outside this loop */
|
||
/* If PARTIAL is 1, GLOBAL means something different:
|
||
that the reg is live outside the range from where it is set
|
||
to the following label. */
|
||
unsigned int done : 1; /* 1 inhibits further processing of this */
|
||
/* 1 in PARTIAL means this reg is used for zero-extending.
|
||
In particular, moving it does not make it invariant. */
|
||
unsigned int partial : 1;
|
||
enum machine_mode savemode; /* Nonzero means it is a mode for a low part
|
||
that we should avoid changing when clearing
|
||
the rest of the reg. */
|
||
struct movable *match; /* First entry for same value */
|
||
struct movable *forces; /* An insn that must be moved if this is */
|
||
struct movable *next;
|
||
};
|
||
|
||
static FILE *loop_dump_stream;
|
||
|
||
/* Forward declarations. */
|
||
|
||
struct induction;
|
||
struct iv_class;
|
||
|
||
static rtx verify_loop ();
|
||
static int invariant_p ();
|
||
static int consec_sets_invariant_p ();
|
||
static int can_jump_into_range_p ();
|
||
static int labels_in_range_p ();
|
||
static void count_loop_regs_set ();
|
||
static void note_addr_stored ();
|
||
static int loop_reg_used_before_p ();
|
||
static void constant_high_bytes ();
|
||
static void scan_loop ();
|
||
static rtx replace_regs ();
|
||
static void replace_call_address ();
|
||
static rtx skip_consec_insns ();
|
||
static void ignore_some_movables ();
|
||
static void force_movables ();
|
||
static void combine_movables ();
|
||
static int rtx_equal_for_loop_p ();
|
||
static void move_movables ();
|
||
static void strength_reduce ();
|
||
static void find_mem_givs ();
|
||
static void record_giv ();
|
||
static void delete_insn_forces ();
|
||
static int basic_induction_var ();
|
||
static int general_induction_var ();
|
||
static int consec_sets_giv ();
|
||
static int check_dbra_loop ();
|
||
static void emit_iv_init_code ();
|
||
static int product_cheap_p ();
|
||
static void emit_iv_inc ();
|
||
static void check_eliminate_biv ();
|
||
static int can_eliminate_biv_p ();
|
||
static void eliminate_biv ();
|
||
static rtx final_biv_value ();
|
||
static int last_use_this_basic_block ();
|
||
|
||
/* Entry point of this file. Perform loop optimization
|
||
on the current function. F is the first insn of the function
|
||
and DUMPFILE is a stream for output of a trace of actions taken
|
||
(or 0 if none should be output). */
|
||
|
||
void
|
||
loop_optimize (f, dumpfile)
|
||
/* f is the first instruction of a chain of insns for one function */
|
||
rtx f;
|
||
FILE *dumpfile;
|
||
{
|
||
register rtx insn;
|
||
register int i;
|
||
rtx end;
|
||
rtx last_insn;
|
||
|
||
loop_dump_stream = dumpfile;
|
||
|
||
init_recog ();
|
||
|
||
old_max_reg = max_reg_num ();
|
||
|
||
moved_once = (char *) alloca (old_max_reg);
|
||
bzero (moved_once, old_max_reg);
|
||
|
||
/* First find the last real insn, and count the number of insns,
|
||
and assign insns their luids. */
|
||
|
||
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
|
||
if (INSN_UID (insn) > i)
|
||
i = INSN_UID (insn);
|
||
|
||
max_uid = i + 1;
|
||
uid_luid = (short *) alloca ((i + 1) * sizeof (short));
|
||
bzero (uid_luid, (i + 1) * sizeof (short));
|
||
|
||
/* Compute the mapping from uids to luids.
|
||
LUIDs are numbers assigned to insns, like uids,
|
||
except that luids increase monotonically through the code.
|
||
Don't assign luids to line-number NOTEs, so that the distance in luids
|
||
between two insns is not affected by -g. */
|
||
|
||
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
|
||
{
|
||
last_insn = insn;
|
||
if (GET_CODE (insn) != NOTE
|
||
|| NOTE_LINE_NUMBER (insn) < 0)
|
||
INSN_LUID (insn) = ++i;
|
||
else
|
||
/* Give a line number note the same luid as preceding insn. */
|
||
INSN_LUID (insn) = i;
|
||
}
|
||
|
||
max_luid = i;
|
||
|
||
/* Don't leave gaps in uid_luid for insns that have been
|
||
deleted. It is possible that the first or last insn
|
||
using some register has been deleted by cross-jumping.
|
||
Make sure that uid_luid for that former insn's uid
|
||
points to the general area where that insn used to be. */
|
||
for (i = 0; i < max_uid; i++)
|
||
{
|
||
uid_luid[0] = uid_luid[i];
|
||
if (uid_luid[0] != 0)
|
||
break;
|
||
}
|
||
for (i = 0; i < max_uid; i++)
|
||
if (uid_luid[i] == 0)
|
||
uid_luid[i] = uid_luid[i - 1];
|
||
|
||
/* Find and process each loop.
|
||
We scan from the end, and process each loop when its start is seen,
|
||
so we process innermost loops first. */
|
||
|
||
for (insn = last_insn; insn; insn = PREV_INSN (insn))
|
||
if (GET_CODE (insn) == NOTE
|
||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
|
||
{
|
||
/* Make sure it really is a loop -- no jumps in from outside. */
|
||
end = verify_loop (f, insn);
|
||
if (end != 0)
|
||
/* If so, optimize this loop. */
|
||
scan_loop (insn, end, max_reg_num ());
|
||
else if (loop_dump_stream)
|
||
fprintf (loop_dump_stream,
|
||
"\nLoop at %d ignored due to multiple entry points.\n",
|
||
INSN_UID (insn));
|
||
}
|
||
}
|
||
|
||
/* Optimize one loop whose start is LOOP_START and end is END.
|
||
LOOP_START is the NOTE_INSN_LOOP_BEG and END is the matching
|
||
NOTE_INSN_LOOP_END. */
|
||
|
||
/* ??? can also move memory writes out of loop if destination
|
||
address is invariant? */
|
||
|
||
static void
|
||
scan_loop (loop_start, end, nregs)
|
||
rtx loop_start, end;
|
||
int nregs;
|
||
{
|
||
register int i;
|
||
register rtx p = NEXT_INSN (loop_start);
|
||
/* 1 if we are scanning insns that could be executed zero times. */
|
||
int maybe_never = 0;
|
||
/* 1 if we are scanning insns that might never be executed
|
||
due to a subroutine call which might exit before they are reached. */
|
||
int call_passed = 0;
|
||
/* For a rotated loop that is entered near the bottom,
|
||
this is the label at the top. Otherwise it is zero. */
|
||
rtx loop_top = 0;
|
||
/* Jump insn that enters the loop, or 0 if control drops in. */
|
||
rtx loop_entry_jump = 0;
|
||
/* Place in the loop where control enters. */
|
||
rtx scan_start;
|
||
/* Number of insns in the loop. */
|
||
int insn_count;
|
||
int tem;
|
||
rtx temp;
|
||
/* Indexed by register number, contains 1 for a register whose
|
||
assignments may not be moved out of the loop. */
|
||
char *may_not_move;
|
||
/* Chain describing insns movable in current loop. */
|
||
struct movable *movables = 0;
|
||
/* Last element in `movables' -- so we can add elements at the end. */
|
||
struct movable *last_movable = 0;
|
||
/* Ratio of extra register life span we can justify
|
||
for saving an instruction. More if loop doesn't call subroutines
|
||
since in that case saving an insn makes more difference
|
||
and more registers are available. */
|
||
int threshold = loop_has_call ? 15 : 30;
|
||
/* Nonzero if the insn that jumps into the real loop
|
||
is not the very first thing after the loop-beginning note. */
|
||
int something_before_entry_jump = 0;
|
||
|
||
n_times_set = (short *) alloca (nregs * sizeof (short));
|
||
n_times_used = (short *) alloca (nregs * sizeof (short));
|
||
may_not_move = (char *) alloca (nregs);
|
||
|
||
/* Determine whether this loop starts with a jump down
|
||
to a test at the end. */
|
||
while (p != end
|
||
&& GET_CODE (p) != CODE_LABEL && GET_CODE (p) != JUMP_INSN)
|
||
{
|
||
if (GET_CODE (p) == CALL_INSN || GET_CODE (p) == INSN)
|
||
something_before_entry_jump = 1;
|
||
p = NEXT_INSN (p);
|
||
}
|
||
|
||
/* "Loop" contains neither jumps nor labels;
|
||
it must have been a dummy. Think no more about it. */
|
||
if (p == end)
|
||
return;
|
||
|
||
scan_start = p;
|
||
|
||
/* If loop has a jump before the first label,
|
||
the true entry is the target of that jump.
|
||
Start scan from there.
|
||
But record in LOOP_TOP the place where the end-test jumps
|
||
back to so we can scan that after the end of the loop. */
|
||
if (GET_CODE (p) == JUMP_INSN)
|
||
{
|
||
loop_entry_jump = p;
|
||
loop_top = NEXT_INSN (p);
|
||
/* Loop entry will never be a conditional jump.
|
||
If we see one, this must not be a real loop.
|
||
Also, a return-insn isn't a jump to enter the loop. */
|
||
if (GET_CODE (loop_top) != BARRIER
|
||
|| GET_CODE (PATTERN (p)) != SET)
|
||
return;
|
||
/* Get the label at which the loop is entered. */
|
||
p = XEXP (SET_SRC (PATTERN (p)), 0);
|
||
/* Check to see whether the jump actually
|
||
jumps out of the loop (meaning it's no loop).
|
||
This case can happen for things like
|
||
do {..} while (0). */
|
||
if (p == 0
|
||
|| INSN_LUID (p) < INSN_LUID (loop_start)
|
||
|| INSN_LUID (p) >= INSN_LUID (end))
|
||
{
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "\nLoop from %d to %d is phony.\n\n",
|
||
INSN_UID (loop_start), INSN_UID (end));
|
||
return;
|
||
}
|
||
|
||
/* Find the first label after the entry-jump. */
|
||
while (GET_CODE (loop_top) != CODE_LABEL)
|
||
{
|
||
loop_top = NEXT_INSN (loop_top);
|
||
if (loop_top == 0)
|
||
abort ();
|
||
}
|
||
|
||
/* Maybe rearrange the loop to drop straight in
|
||
with a new test to jump around it entirely.
|
||
(The latter is considered outside the loop.)
|
||
If this is done, we no longer enter with a jump. */
|
||
if (! something_before_entry_jump
|
||
&& loop_skip_over (loop_start, end, loop_entry_jump))
|
||
{
|
||
scan_start = loop_top;
|
||
loop_top = 0;
|
||
}
|
||
else
|
||
/* We really do enter with a jump;
|
||
scan the loop from the place where the jump jumps to. */
|
||
scan_start = p;
|
||
}
|
||
|
||
/* Count number of times each reg is set during this loop.
|
||
Set MAY_NOT_MOVE[I] if it is not safe to move out
|
||
the setting of register I. */
|
||
|
||
bzero (n_times_set, nregs * sizeof (short));
|
||
bzero (may_not_move, nregs);
|
||
count_loop_regs_set (loop_top ? loop_top : loop_start, end,
|
||
may_not_move, &insn_count, nregs);
|
||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||
may_not_move[i] = 1, n_times_set[i] = 1;
|
||
bcopy (n_times_set, n_times_used, nregs * sizeof (short));
|
||
|
||
if (loop_dump_stream)
|
||
{
|
||
fprintf (loop_dump_stream, "\nLoop from %d to %d: %d real insns.\n",
|
||
INSN_UID (loop_start), INSN_UID (end), insn_count);
|
||
if (loop_continue)
|
||
fprintf (loop_dump_stream, "Continue at insn %d.\n",
|
||
INSN_UID (loop_continue));
|
||
}
|
||
|
||
/* Scan through the loop finding insns that are safe to move.
|
||
In each such insn, store QImode as the mode, to mark it.
|
||
Then set n_times_set to -1 for the reg being set, so that
|
||
this reg will be considered invariant for subsequent insns.
|
||
We consider whether subsequent insns use the reg
|
||
in deciding whether it is worth actually moving.
|
||
|
||
MAYBE_NEVER is nonzero if we have passed a conditional jump insn
|
||
and therefore it is possible that the insns we are scanning
|
||
would never be executed. At such times, we must make sure
|
||
that it is safe to execute the insn once instead of zero times.
|
||
When MAYBE_NEVER is 0, all insns will be executed at least once
|
||
so that is not a problem. */
|
||
|
||
p = scan_start;
|
||
while (1)
|
||
{
|
||
p = NEXT_INSN (p);
|
||
/* At end of a straight-in loop, we are done.
|
||
At end of a loop entered at the bottom, scan the top. */
|
||
if (p == scan_start)
|
||
break;
|
||
if (p == end)
|
||
{
|
||
if (loop_top != 0)
|
||
p = NEXT_INSN (loop_top);
|
||
else
|
||
break;
|
||
if (p == scan_start)
|
||
break;
|
||
}
|
||
if (GET_CODE (p) == INSN
|
||
&& GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG
|
||
&& ! may_not_move[REGNO (SET_DEST (PATTERN (p)))])
|
||
{
|
||
int tem1 = 0;
|
||
/* Don't try to optimize a register that was made
|
||
by loop-optimization for an inner loop.
|
||
We don't know its life-span, so we can't compute the benefit. */
|
||
if (REGNO (SET_DEST (PATTERN (p))) >= old_max_reg)
|
||
;
|
||
/* If this register is used or set outside the loop,
|
||
then we can move it only if we know this insn is
|
||
executed exactly once per iteration,
|
||
and we can check all the insns executed before it
|
||
to make sure none of them used the value that
|
||
was lying around at entry to the loop. */
|
||
else if ((uid_luid[regno_last_uid[REGNO (SET_DEST (PATTERN (p)))]] > INSN_LUID (end)
|
||
|| uid_luid[regno_first_uid[REGNO (SET_DEST (PATTERN (p)))]] < INSN_LUID (loop_start))
|
||
&& (maybe_never
|
||
|| loop_reg_used_before_p (p, loop_start, scan_start, end)))
|
||
;
|
||
else if (((tem = invariant_p (SET_SRC (PATTERN (p))))
|
||
|| ((temp = find_reg_note (p, REG_EQUAL, 0))
|
||
&& (tem = invariant_p (XEXP (temp, 0)))))
|
||
&& (n_times_set[REGNO (SET_DEST (PATTERN (p)))] == 1
|
||
|| (tem1
|
||
= consec_sets_invariant_p (SET_DEST (PATTERN (p)),
|
||
n_times_set[REGNO (SET_DEST (PATTERN (p)))],
|
||
p)))
|
||
/* If the insn can cause a trap (such as divide by zero),
|
||
can't move it unless it's guaranteed to be executed
|
||
once loop is entered. Even a function call might
|
||
prevent the trap insn from being reached
|
||
(since it might exit!) */
|
||
&& ! ((maybe_never || call_passed)
|
||
&& (may_trap_p (SET_SRC (PATTERN (p)))
|
||
|| ((temp = find_reg_note (p, REG_EQUAL, 0))
|
||
&& may_trap_p (XEXP (temp, 0))))))
|
||
{
|
||
register struct movable *m;
|
||
register int regno = REGNO (SET_DEST (PATTERN (p)));
|
||
int count;
|
||
m = (struct movable *) alloca (sizeof (struct movable));
|
||
m->next = 0;
|
||
m->insn = p;
|
||
temp = find_reg_note (p, REG_EQUAL, 0);
|
||
if (temp)
|
||
m->set_src = XEXP (temp, 0);
|
||
else
|
||
m->set_src = SET_SRC (PATTERN (p));
|
||
m->force = 0;
|
||
m->consec = n_times_set[REGNO (SET_DEST (PATTERN (p)))] - 1;
|
||
m->done = 0;
|
||
m->forces = 0;
|
||
m->partial = 0;
|
||
m->savemode = VOIDmode;
|
||
m->regno = regno;
|
||
/* Set M->cond if either invariant_p or consec_sets_invariant_p
|
||
returned 2 (only conditionally invariant). */
|
||
m->cond = ((tem | tem1) > 1);
|
||
m->global = (uid_luid[regno_last_uid[regno]] > INSN_LUID (end)
|
||
|| uid_luid[regno_first_uid[regno]] < INSN_LUID (loop_start));
|
||
m->match = 0;
|
||
m->lifetime = (uid_luid[regno_last_uid[regno]]
|
||
- uid_luid[regno_first_uid[regno]]);
|
||
m->savings = n_times_used[regno];
|
||
n_times_set[regno] = -1;
|
||
/* Add M to the end of the chain MOVABLES. */
|
||
if (movables == 0)
|
||
movables = m;
|
||
else
|
||
last_movable->next = m;
|
||
last_movable = m;
|
||
if (m->consec > 0)
|
||
{
|
||
/* Skip this insn, not checking REG_LIBCALL notes. */
|
||
p = NEXT_INSN (p);
|
||
/* Skip the consecutive insns, if there are any. */
|
||
p = skip_consec_insns (p, m->consec);
|
||
/* Back up, so the main loop will advance to the right place. */
|
||
p = PREV_INSN (p);
|
||
}
|
||
}
|
||
/* If this register is always set within a STRICT_LOW_PART
|
||
or set to zero, then its high bytes are constant.
|
||
So clear them outside the loop and within the loop
|
||
just load the low bytes.
|
||
We must check that the machine has an instruction to do so.
|
||
Also, if the value loaded into the register
|
||
depends on the same register, this cannot be done. */
|
||
else if (SET_SRC (PATTERN (p)) == const0_rtx
|
||
&& GET_CODE (NEXT_INSN (p)) == INSN
|
||
&& GET_CODE (PATTERN (NEXT_INSN (p))) == SET
|
||
&& (GET_CODE (SET_DEST (PATTERN (NEXT_INSN (p))))
|
||
== STRICT_LOW_PART)
|
||
&& (GET_CODE (XEXP (SET_DEST (PATTERN (NEXT_INSN (p))), 0))
|
||
== SUBREG)
|
||
&& (SUBREG_REG (XEXP (SET_DEST (PATTERN (NEXT_INSN (p))), 0))
|
||
== SET_DEST (PATTERN (p)))
|
||
&& !reg_mentioned_p (SET_DEST (PATTERN (p)),
|
||
SET_SRC (PATTERN (NEXT_INSN (p)))))
|
||
{
|
||
register int regno = REGNO (SET_DEST (PATTERN (p)));
|
||
if (n_times_set[regno] == 2)
|
||
{
|
||
register struct movable *m;
|
||
int count;
|
||
m = (struct movable *) alloca (sizeof (struct movable));
|
||
m->next = 0;
|
||
m->insn = p;
|
||
m->force = 0;
|
||
m->consec = 0;
|
||
m->done = 0;
|
||
m->forces = 0;
|
||
m->partial = 1;
|
||
/* If the insn may not be executed on some cycles,
|
||
we can't clear the whole reg; clear just high part.
|
||
Not even if the reg is used only within this loop.
|
||
Consider this:
|
||
while (1)
|
||
while (s != t) {
|
||
if (foo ()) x = *s;
|
||
use (x);
|
||
}
|
||
Clearing x before the inner loop could clobber a value
|
||
being saved from the last time around the outer loop.
|
||
However, if the reg is not used outside this loop
|
||
and all uses of the register are in the same
|
||
basic block as the store, there is no problem. */
|
||
m->global = (uid_luid[regno_last_uid[regno]] > INSN_LUID (end)
|
||
|| uid_luid[regno_first_uid[regno]] < INSN_LUID (p)
|
||
|| (labels_in_range_p
|
||
(p, uid_luid[regno_first_uid[regno]])));
|
||
if (maybe_never && m->global)
|
||
m->savemode = GET_MODE (SET_SRC (PATTERN (NEXT_INSN (p))));
|
||
else
|
||
m->savemode = VOIDmode;
|
||
m->regno = regno;
|
||
m->cond = 0;
|
||
m->match = 0;
|
||
m->lifetime = (uid_luid[regno_last_uid[regno]]
|
||
- uid_luid[regno_first_uid[regno]]);
|
||
m->savings = 1;
|
||
n_times_set[regno] = -1;
|
||
/* Add M to the end of the chain MOVABLES. */
|
||
if (movables == 0)
|
||
movables = m;
|
||
else
|
||
last_movable->next = m;
|
||
last_movable = m;
|
||
}
|
||
}
|
||
}
|
||
/* Past a call insn, we get to insns which might not be executed
|
||
because the call might exit. This matters for insns that trap. */
|
||
else if (GET_CODE (p) == CALL_INSN)
|
||
call_passed = 1;
|
||
/* Past a label or a jump, we get to insns for which we
|
||
can't count on whether or how many times they will be
|
||
executed during each iteration. Therefore, we can
|
||
only move out sets of trivial variables
|
||
(those not used after the loop). */
|
||
else if ((GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
|
||
/* If we enter the loop in the middle, and scan around
|
||
to the beginning, don't set maybe_never for that. */
|
||
&& ! (NEXT_INSN (p) == end && GET_CODE (p) == JUMP_INSN
|
||
&& simplejump_p (p)))
|
||
maybe_never = 1;
|
||
}
|
||
|
||
/* If one movable subsumes another, ignore that other. */
|
||
|
||
ignore_some_movables (movables);
|
||
|
||
/* For each movable insn, see if the reg that it loads
|
||
leads when it dies right into another conditionally movable insn.
|
||
If so, record that the second insn "forces" the first one,
|
||
since the second can be moved only if the first is. */
|
||
|
||
force_movables (movables);
|
||
|
||
/* See if there are multiple movable insns that load the same value.
|
||
If there are, make all but the first point at the first one
|
||
through the `match' field, and add the priorities of them
|
||
all together as the priority of the first. */
|
||
|
||
combine_movables (movables, nregs);
|
||
|
||
/* Now consider each movable insn to decide whether it is worth moving.
|
||
Store 0 in n_times_set for each reg that is moved. */
|
||
|
||
move_movables (movables, threshold,
|
||
insn_count, loop_start, end, nregs);
|
||
|
||
/* Now candidates that still have -1 are those not moved.
|
||
Change n_times_set to indicate that those are not actually invariant. */
|
||
for (i = 0; i < nregs; i++)
|
||
if (n_times_set[i] < 0)
|
||
n_times_set[i] = n_times_used[i];
|
||
|
||
if (flag_strength_reduce)
|
||
strength_reduce (scan_start, end, loop_top,
|
||
insn_count, loop_start, end, nregs);
|
||
}
|
||
|
||
/* Skip COUNT insns from INSN, counting library calls as 1 insn. */
|
||
|
||
static rtx
|
||
skip_consec_insns (insn, count)
|
||
rtx insn;
|
||
int count;
|
||
{
|
||
for (; count > 0; count--)
|
||
{
|
||
if (GET_CODE (insn) == NOTE)
|
||
insn = NEXT_INSN (insn);
|
||
else if (GET_CODE (insn) == BARRIER || GET_CODE (insn) == CODE_LABEL)
|
||
abort ();
|
||
else
|
||
{
|
||
rtx i1, temp;
|
||
|
||
/* If first insn of gnulib call sequence, skip to end. */
|
||
/* Do this at start of loop, since INSN is guaranteed to
|
||
be an insn here. */
|
||
if (temp = find_reg_note (insn, REG_LIBCALL, 0))
|
||
insn = XEXP (temp, 0);
|
||
|
||
do insn = NEXT_INSN (insn);
|
||
while (GET_CODE (insn) == NOTE);
|
||
}
|
||
}
|
||
|
||
return insn;
|
||
}
|
||
|
||
/* Ignore any movable whose insn falls within a libcall
|
||
which is part of another movable.
|
||
We make use of the fact that the movable for the libcall value
|
||
was made later and so appears later on the chain. */
|
||
|
||
static void
|
||
ignore_some_movables (movables)
|
||
struct movable *movables;
|
||
{
|
||
register struct movable *m, *m1;
|
||
|
||
for (m = movables; m; m = m->next)
|
||
{
|
||
/* Is this a movable for the value of a libcall? */
|
||
rtx note = find_reg_note (m->insn, REG_RETVAL, 0);
|
||
if (note)
|
||
{
|
||
/* Find the beginning of that libcall. */
|
||
rtx first_insn = XEXP (note, 0);
|
||
/* Check for earlier movables inside that range,
|
||
and mark them invalid. */
|
||
for (m1 = movables; m1 != m; m1 = m1->next)
|
||
if (INSN_LUID (m1->insn) >= INSN_LUID (first_insn)
|
||
&& INSN_LUID (m1->insn) < INSN_LUID (m->insn))
|
||
m1->done = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* For each movable insn, see if the reg that it loads
|
||
leads when it dies right into another conditionally movable insn.
|
||
If so, record that the second insn "forces" the first one,
|
||
since the second can be moved only if the first is. */
|
||
|
||
static void
|
||
force_movables (movables)
|
||
struct movable *movables;
|
||
{
|
||
register struct movable *m, *m1;
|
||
for (m1 = movables; m1; m1 = m1->next)
|
||
/* Omit this if moving just the (SET (REG) 0) of a zero-extend. */
|
||
if (!m1->partial && !m1->done)
|
||
{
|
||
int regno = m1->regno;
|
||
for (m = m1->next; m; m = m->next)
|
||
/* ??? Could this be a bug? What if CSE caused the
|
||
register of M1 to be used after this insn?
|
||
Since CSE does not update regno_last_uid,
|
||
this insn M->insn might not be where it dies.
|
||
But very likely this doesn't matter; what matters is
|
||
that M's reg is computed from M1's reg. */
|
||
if (INSN_UID (m->insn) == regno_last_uid[regno]
|
||
&& !m->done)
|
||
break;
|
||
if (m != 0 && m->set_src == SET_DEST (PATTERN (m1->insn)))
|
||
m = 0;
|
||
|
||
/* Increase the priority of the moving the first insn
|
||
since it permits the second to be moved as well. */
|
||
if (m != 0)
|
||
{
|
||
m->forces = m1;
|
||
m1->lifetime += m->lifetime;
|
||
m1->savings += m1->savings;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Find invariant expressions that are equal and can be combined into
|
||
one register. */
|
||
|
||
static void
|
||
combine_movables (movables, nregs)
|
||
struct movable *movables;
|
||
int nregs;
|
||
{
|
||
register struct movable *m;
|
||
char *matched_regs = (char *) alloca (nregs);
|
||
enum machine_mode mode;
|
||
|
||
/* Regs that are set more than once are not allowed to match
|
||
or be matched. I'm no longer sure why not. */
|
||
/* Perhaps testing m->consec_sets would be more appropriate here? */
|
||
|
||
for (m = movables; m; m = m->next)
|
||
if (m->match == 0 && n_times_used[m->regno] == 1 && !m->partial)
|
||
{
|
||
register struct movable *m1;
|
||
int regno = m->regno;
|
||
|
||
bzero (matched_regs, nregs);
|
||
matched_regs[regno] = 1;
|
||
|
||
for (m1 = m->next; m1; m1 = m1->next)
|
||
if (m1->match == 0 && n_times_used[m1->regno] == 1
|
||
/* A reg used outside the loop mustn't be eliminated. */
|
||
&& !m1->global
|
||
/* A reg used for zero-extending mustn't be eliminated. */
|
||
&& !m1->partial
|
||
&& (matched_regs[m1->regno]
|
||
||
|
||
(
|
||
/* Can't combine regs with different modes
|
||
even if loaded from the same constant. */
|
||
(GET_MODE (SET_DEST (PATTERN (m->insn)))
|
||
== GET_MODE (SET_DEST (PATTERN (m1->insn))))
|
||
/* See if the source of M1 says it matches M. */
|
||
&& ((GET_CODE (m1->set_src) == REG
|
||
&& matched_regs[REGNO (m1->set_src)])
|
||
|| rtx_equal_for_loop_p (m->set_src, m1->set_src,
|
||
movables)
|
||
|| (REG_NOTES (m->insn) && REG_NOTES (m1->insn)
|
||
&& REG_NOTE_KIND (REG_NOTES (m->insn)) == REG_EQUIV
|
||
&& REG_NOTE_KIND (REG_NOTES (m1->insn)) == REG_EQUIV
|
||
&& rtx_equal_p (XEXP (REG_NOTES (m->insn), 0),
|
||
XEXP (REG_NOTES (m1->insn), 0)))))))
|
||
{
|
||
m->lifetime += m1->lifetime;
|
||
m->savings += m1->savings;
|
||
m1->match = m;
|
||
matched_regs[m1->regno] = 1;
|
||
}
|
||
}
|
||
|
||
/* Now combine the regs used for zero-extension.
|
||
This can be done for those not marked `global'
|
||
provided their lives don't overlap. */
|
||
|
||
for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
|
||
mode = (enum machine_mode) ((int) mode + 1))
|
||
if (GET_MODE_CLASS (mode) == MODE_INT)
|
||
{
|
||
register struct movable *m0 = 0;
|
||
|
||
/* Combine all the registers for extension from mode MODE.
|
||
Don't combine any that are used outside this loop. */
|
||
for (m = movables; m; m = m->next)
|
||
if (m->partial && ! m->global
|
||
&& mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn)))))
|
||
{
|
||
register struct movable *m1;
|
||
int first = uid_luid[regno_first_uid[m->regno]];
|
||
int last = uid_luid[regno_last_uid[m->regno]];
|
||
|
||
if (m0 == 0)
|
||
{
|
||
/* First one: don't check for overlap, just record it. */
|
||
m0 = m;
|
||
continue;
|
||
}
|
||
|
||
/* Make sure they extend to the same mode.
|
||
(Almost always true.) */
|
||
if (GET_MODE (SET_DEST (PATTERN (m->insn)))
|
||
!= GET_MODE (SET_DEST (PATTERN (m0->insn))))
|
||
continue;
|
||
|
||
/* We already have one: check for overlap with those
|
||
already combined together. */
|
||
for (m1 = movables; m1 != m; m1 = m1->next)
|
||
if (m1 == m0 || (m1->partial && m1->match == m0))
|
||
if (! (uid_luid[regno_first_uid[m1->regno]] > last
|
||
|| uid_luid[regno_last_uid[m1->regno]] < first))
|
||
goto overlap;
|
||
|
||
/* No overlap: we can combine this with the others. */
|
||
m0->lifetime += m->lifetime;
|
||
m0->savings += m->savings;
|
||
m->match = m0;
|
||
|
||
overlap: ;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Return 1 if regs X and Y will become the same if moved. */
|
||
|
||
static int
|
||
regs_match_p (x, y, movables)
|
||
rtx x, y;
|
||
struct movable *movables;
|
||
{
|
||
int xn = REGNO (x);
|
||
int yn = REGNO (y);
|
||
struct movable *mx, *my;
|
||
|
||
for (mx = movables; mx; mx = mx->next)
|
||
if (mx->regno == xn)
|
||
break;
|
||
|
||
for (my = movables; my; my = my->next)
|
||
if (my->regno == yn)
|
||
break;
|
||
|
||
return (mx && my
|
||
&& ((mx->match == my->match && mx->match != 0)
|
||
|| mx->match == my
|
||
|| mx == my->match));
|
||
}
|
||
|
||
/* Return 1 if X and Y are identical-looking rtx's.
|
||
This is the Lisp function EQUAL for rtx arguments. */
|
||
|
||
static int
|
||
rtx_equal_for_loop_p (x, y, movables)
|
||
rtx x, y;
|
||
struct movable *movables;
|
||
{
|
||
register int i;
|
||
register int j;
|
||
register enum rtx_code code;
|
||
register char *fmt;
|
||
|
||
if (x == y)
|
||
return 1;
|
||
if (x == 0 || y == 0)
|
||
return 0;
|
||
|
||
code = GET_CODE (x);
|
||
/* Rtx's of different codes cannot be equal. */
|
||
if (code != GET_CODE (y))
|
||
return 0;
|
||
|
||
/* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
|
||
(REG:SI x) and (REG:HI x) are NOT equivalent. */
|
||
|
||
if (GET_MODE (x) != GET_MODE (y))
|
||
return 0;
|
||
|
||
/* These three types of rtx's can be compared nonrecursively. */
|
||
/* Until the end of reload,
|
||
don't consider the a reference to the return register of the current
|
||
function the same as the return from a called function. This eases
|
||
the job of function integration. Once the distinction no longer
|
||
matters, the insn will be deleted. */
|
||
if (code == REG)
|
||
return ((REGNO (x) == REGNO (y)
|
||
&& REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y))
|
||
|| regs_match_p (x, y, movables));
|
||
|
||
if (code == LABEL_REF)
|
||
return XEXP (x, 0) == XEXP (y, 0);
|
||
if (code == SYMBOL_REF)
|
||
return XSTR (x, 0) == XSTR (y, 0);
|
||
|
||
/* Compare the elements. If any pair of corresponding elements
|
||
fail to match, return 0 for the whole things. */
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
switch (fmt[i])
|
||
{
|
||
case 'i':
|
||
if (XINT (x, i) != XINT (y, i))
|
||
return 0;
|
||
break;
|
||
|
||
case 'E':
|
||
/* Two vectors must have the same length. */
|
||
if (XVECLEN (x, i) != XVECLEN (y, i))
|
||
return 0;
|
||
|
||
/* And the corresponding elements must match. */
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
if (rtx_equal_for_loop_p (XVECEXP (x, i, j), XVECEXP (y, i, j), movables) == 0)
|
||
return 0;
|
||
break;
|
||
|
||
case 'e':
|
||
if (rtx_equal_for_loop_p (XEXP (x, i), XEXP (y, i), movables) == 0)
|
||
return 0;
|
||
break;
|
||
|
||
case 's':
|
||
if (strcmp (XSTR (x, i), XSTR (y, i)))
|
||
return 0;
|
||
break;
|
||
|
||
case 'u':
|
||
/* These are just backpointers, so they don't matter. */
|
||
break;
|
||
|
||
case '0':
|
||
break;
|
||
|
||
/* It is believed that rtx's at this level will never
|
||
contain anything but integers and other rtx's,
|
||
except for within LABEL_REFs and SYMBOL_REFs. */
|
||
default:
|
||
abort ();
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/* Scan MOVABLES, and move the insns that deserve to be moved.
|
||
If two matching movables are combined, replace one reg with the
|
||
other throughout. */
|
||
|
||
static void
|
||
move_movables (movables, threshold, insn_count, loop_start, end, nregs)
|
||
struct movable *movables;
|
||
int threshold;
|
||
int insn_count;
|
||
rtx loop_start;
|
||
rtx end;
|
||
int nregs;
|
||
{
|
||
rtx new_start = 0;
|
||
register struct movable *m;
|
||
register rtx p;
|
||
/* Map of pseudo-register replacements to handle combining
|
||
when we move several insns that load the same value
|
||
into different pseudo-registers. */
|
||
rtx *reg_map = (rtx *) alloca (nregs * sizeof (rtx));
|
||
char *already_moved = (char *) alloca (nregs);
|
||
|
||
bzero (already_moved, nregs);
|
||
bzero (reg_map, nregs * sizeof (rtx));
|
||
|
||
num_movables = 0;
|
||
|
||
for (m = movables; m; m = m->next)
|
||
{
|
||
/* Describe this movable insn. */
|
||
|
||
if (loop_dump_stream)
|
||
{
|
||
fprintf (loop_dump_stream, "Insn %d: regno %d (life %d), ",
|
||
INSN_UID (m->insn), m->regno, m->lifetime);
|
||
if (m->consec > 0)
|
||
fprintf (loop_dump_stream, "consec %d, ", m->consec);
|
||
if (m->cond)
|
||
fprintf (loop_dump_stream, "cond ");
|
||
if (m->force)
|
||
fprintf (loop_dump_stream, "force ");
|
||
if (m->global)
|
||
fprintf (loop_dump_stream, "global ");
|
||
if (m->done)
|
||
fprintf (loop_dump_stream, "done ");
|
||
if (m->match)
|
||
fprintf (loop_dump_stream, "matches %d ",
|
||
INSN_UID (m->match->insn));
|
||
if (m->forces)
|
||
fprintf (loop_dump_stream, "forces %d ",
|
||
INSN_UID (m->forces->insn));
|
||
}
|
||
|
||
/* Count movables. Value used in heuristics in strength_reduce. */
|
||
num_movables++;
|
||
|
||
/* Ignore the insn if it's already done (it matched something else).
|
||
Otherwise, see if it is now safe to move. */
|
||
|
||
if (!m->done
|
||
&& (! m->cond
|
||
|| (1 == invariant_p (m->set_src)
|
||
&& (m->consec == 0
|
||
|| 1 == consec_sets_invariant_p (SET_DEST (PATTERN (m->insn)),
|
||
m->consec + 1,
|
||
m->insn))))
|
||
&& (! m->forces || m->forces->done))
|
||
{
|
||
register int regno;
|
||
register rtx p;
|
||
int savings = m->savings;
|
||
|
||
/* We have an insn that is safe to move.
|
||
Compute its desirability. */
|
||
|
||
p = m->insn;
|
||
regno = m->regno;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "savings %d ", savings);
|
||
|
||
if (moved_once[regno])
|
||
{
|
||
insn_count *= 2;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "halved since already moved ");
|
||
}
|
||
|
||
/* An insn MUST be moved if we already moved something else
|
||
which is safe only if this one is moved too: that is,
|
||
if already_moved[REGNO] is nonzero. */
|
||
|
||
/* An insn is desirable to move if the new lifetime of the
|
||
register is no more than THRESHOLD times the old lifetime.
|
||
If it's not desirable, it means the loop is so big
|
||
that moving won't speed things up much,
|
||
and it is liable to make register usage worse. */
|
||
|
||
/* It is also desirable to move if it can be moved at no
|
||
extra cost because something else was already moved. */
|
||
|
||
if (already_moved[regno]
|
||
|| (threshold * savings * m->lifetime) >= insn_count
|
||
|| (m->forces && m->forces->done
|
||
&& n_times_used[m->forces->regno] == 1))
|
||
{
|
||
int count;
|
||
register struct movable *m1;
|
||
rtx first;
|
||
|
||
/* Now move the insns that set the reg. */
|
||
|
||
for (count = m->consec; count >= 0; count--)
|
||
{
|
||
rtx i1, temp;
|
||
|
||
/* If first insn of gnulib call sequence, skip to end. */
|
||
/* Do this at start of loop, since p is guaranteed to
|
||
be an insn here. */
|
||
if (temp = find_reg_note (p, REG_LIBCALL, 0))
|
||
p = XEXP (temp, 0);
|
||
|
||
/* If last insn of gnulib call sequence, move all
|
||
insns except the last before the loop. The last insn is
|
||
handled in the normal manner. */
|
||
if (temp = find_reg_note (p, REG_RETVAL
|
||
, 0))
|
||
{
|
||
rtx fn_address = 0;
|
||
rtx fn_reg = 0;
|
||
first = 0;
|
||
for (temp = XEXP (temp, 0); temp != p;
|
||
temp = NEXT_INSN (temp))
|
||
{
|
||
rtx body = PATTERN (temp);
|
||
rtx n;
|
||
/* Extract the function address from the insn
|
||
that loads it into a register.
|
||
If this insn was cse'd, we get incorrect code.
|
||
So delete it and stick the fn address right
|
||
into the call insn. Since the moved insns
|
||
won't be cse'd, that does no harm. */
|
||
if (GET_CODE (NEXT_INSN (temp)) == CALL_INSN
|
||
&& GET_CODE (body) == SET
|
||
&& GET_CODE (SET_DEST (body)) == REG
|
||
&& (n = find_reg_note (temp, REG_EQUIV, 0)))
|
||
{
|
||
fn_reg = SET_SRC (body);
|
||
if (GET_CODE (fn_reg) != REG)
|
||
fn_reg = SET_DEST (body);
|
||
fn_address = XEXP (n, 0);
|
||
continue;
|
||
}
|
||
/* We have the call insn.
|
||
Substitute the fn address for the reg
|
||
that we believe this insn will use. */
|
||
if (GET_CODE (temp) == CALL_INSN
|
||
&& fn_address != 0)
|
||
replace_call_address (body, fn_reg, fn_address);
|
||
if (GET_CODE (temp) == CALL_INSN)
|
||
i1 = emit_call_insn_before (body, loop_start);
|
||
else
|
||
i1 = emit_insn_before (body, loop_start);
|
||
if (first == 0)
|
||
first = i1;
|
||
REG_NOTES (i1) = REG_NOTES (temp);
|
||
delete_insn (temp);
|
||
}
|
||
}
|
||
if (m->savemode != VOIDmode)
|
||
{
|
||
/* P sets REG to zero; but we should clear only the bits
|
||
that are not covered by the mode m->savemode. */
|
||
rtx reg = SET_DEST (PATTERN (p));
|
||
i1 = emit_insn_before
|
||
(gen_rtx (SET, VOIDmode, reg,
|
||
gen_rtx (AND, GET_MODE (reg),
|
||
reg,
|
||
gen_rtx (CONST_INT, VOIDmode,
|
||
(1 << GET_MODE_BITSIZE (m->savemode)) - 1))),
|
||
loop_start);
|
||
}
|
||
else if (GET_CODE (PATTERN (p)) == CALL_INSN)
|
||
i1 = emit_call_insn_before (PATTERN (p), loop_start);
|
||
else
|
||
i1 = emit_insn_before (PATTERN (p), loop_start);
|
||
|
||
if (new_start == 0)
|
||
new_start = i1;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));
|
||
|
||
/* Mark the moved, invariant reg as being equivalent to
|
||
its constant value. */
|
||
REG_NOTES (i1) = REG_NOTES (p);
|
||
if (REG_NOTES (i1) == 0
|
||
&& ! m->partial /* But not if it's a zero-extend clr. */
|
||
&& ! m->global /* and not if used outside the loop
|
||
(since it might get set outside). */
|
||
&& CONSTANT_P (SET_SRC (PATTERN (p))))
|
||
REG_NOTES (i1)
|
||
= gen_rtx (EXPR_LIST, REG_EQUIV,
|
||
SET_SRC (PATTERN (p)), REG_NOTES (i1));
|
||
|
||
/* If library call, now fix the REG_NOTES that contain
|
||
insn pointers, namely REG_LIBCALL on FIRST
|
||
and REG_RETVAL on I1. */
|
||
if (temp = find_reg_note (i1, REG_RETVAL, 0))
|
||
{
|
||
XEXP (temp, 0) = first;
|
||
temp = find_reg_note (first, REG_LIBCALL, 0);
|
||
XEXP (temp, 0) = i1;
|
||
}
|
||
|
||
delete_insn (p);
|
||
do p = NEXT_INSN (p);
|
||
while (GET_CODE (p) == NOTE);
|
||
}
|
||
|
||
/* The more regs we move, the less we like moving them. */
|
||
threshold -= 3;
|
||
|
||
/* Any other movable that loads the same register
|
||
MUST be moved. */
|
||
already_moved[regno] = 1;
|
||
|
||
/* This reg has been moved out of one loop. */
|
||
moved_once[regno] = 1;
|
||
|
||
/* The reg set here is now invariant. */
|
||
if (! m->partial)
|
||
n_times_set[regno] = 0;
|
||
|
||
m->done = 1;
|
||
|
||
/* Change the length-of-life info for the register
|
||
to say it lives at least the full length of this loop.
|
||
This will help guide optimizations in outer loops. */
|
||
|
||
if (uid_luid[regno_first_uid[regno]] > INSN_LUID (loop_start))
|
||
/* This is the old insn before all the moved insns.
|
||
We can't use the moved insn because it is out of range
|
||
in uid_luid. Only the old insns have luids. */
|
||
regno_first_uid[regno] = INSN_UID (loop_start);
|
||
if (uid_luid[regno_last_uid[regno]] < INSN_LUID (end))
|
||
regno_last_uid[regno] = INSN_UID (end);
|
||
|
||
/* Combine with this moved insn any other matching movables. */
|
||
|
||
for (m1 = m->next; m1; m1 = m1->next)
|
||
if (m1->match == m)
|
||
{
|
||
rtx temp;
|
||
|
||
/* Schedule the reg loaded by M1
|
||
for replacement so that shares the reg of M. */
|
||
reg_map[m1->regno] = SET_DEST (PATTERN (m->insn));
|
||
/* Get rid of the matching insn
|
||
and prevent further processing of it. */
|
||
m1->done = 1;
|
||
|
||
/* if library call, delete all insn except last, which
|
||
is deleted below */
|
||
if (temp = find_reg_note (m1->insn, REG_RETVAL, 0))
|
||
{
|
||
for (temp = XEXP (temp, 0); temp != m1->insn;
|
||
temp = NEXT_INSN (temp))
|
||
delete_insn (temp);
|
||
}
|
||
delete_insn (m1->insn);
|
||
|
||
/* Any other movable that loads the same register
|
||
MUST be moved. */
|
||
already_moved[m1->regno] = 1;
|
||
|
||
/* The reg merged here is now invariant,
|
||
if the reg it matches is invariant. */
|
||
if (! m->partial)
|
||
n_times_set[m1->regno] = 0;
|
||
}
|
||
}
|
||
else if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "not desirable");
|
||
}
|
||
else if (loop_dump_stream && !m->match)
|
||
fprintf (loop_dump_stream, "not safe");
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "\n");
|
||
}
|
||
|
||
if (new_start == 0)
|
||
new_start = loop_start;
|
||
|
||
/* Go through all the instructions in the loop, making
|
||
all the register substitutions scheduled in REG_MAP. */
|
||
for (p = new_start; p != end; p = NEXT_INSN (p))
|
||
if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
|
||
|| GET_CODE (p) == CALL_INSN)
|
||
replace_regs (PATTERN (p), reg_map, nregs);
|
||
}
|
||
|
||
/* Optionally change a loop which enters just before the endtest
|
||
to one which falls straight in
|
||
after skipping around the entire loop if the endtest would drop out.
|
||
Returns 1 if the change was made, 0 if the loop was not really suitable. */
|
||
|
||
int
|
||
loop_skip_over (start, end, loop_entry_jump)
|
||
rtx start;
|
||
rtx end;
|
||
rtx loop_entry_jump;
|
||
{
|
||
rtx endtestjump;
|
||
register rtx p = JUMP_LABEL (loop_entry_jump);
|
||
|
||
while (GET_CODE (p) != INSN && GET_CODE (p) != JUMP_INSN
|
||
&& GET_CODE (p) != CALL_INSN)
|
||
p = NEXT_INSN (p);
|
||
endtestjump = next_real_insn (p);
|
||
|
||
/* Check that we (1) enter at a compare insn and (2)
|
||
the insn (presumably a jump) following that compare
|
||
is the last in the loop and jumps back to the loop beginning. */
|
||
|
||
if (sets_cc0_p (PATTERN (p)) > 0
|
||
&& endtestjump == prev_real_insn (end)
|
||
&& prev_real_insn (JUMP_LABEL (endtestjump)) == loop_entry_jump)
|
||
{
|
||
rtx newlab;
|
||
/* This is the jump that we insert. */
|
||
rtx new_jump;
|
||
|
||
/* Ok, duplicate that test before start of loop. */
|
||
emit_insn_before (copy_rtx (PATTERN (p)), start);
|
||
/* Make a new entry-jump (before the original one)
|
||
whose condition is opposite to the loop-around endtest
|
||
and which jumps around the loop (to just after the ending NOTE). */
|
||
newlab = gen_label_rtx ();
|
||
emit_label_after (newlab, end);
|
||
emit_jump_insn_before (copy_rtx (PATTERN (endtestjump)), start);
|
||
new_jump = PREV_INSN (start);
|
||
JUMP_LABEL (new_jump) = JUMP_LABEL (endtestjump);
|
||
LABEL_NUSES (JUMP_LABEL (endtestjump))++;
|
||
invert_jump (new_jump, newlab);
|
||
/* Delete the original entry-jump. */
|
||
delete_insn (loop_entry_jump);
|
||
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Throughout the rtx X, replace many registers according to REG_MAP.
|
||
Return the replacement for X (which may be X with altered contents).
|
||
REG_MAP[R] is the replacement for register R, or 0 for don't replace.
|
||
NREGS is the length of REG_MAP; regs >= NREGS are not mapped. */
|
||
|
||
static rtx
|
||
replace_regs (x, reg_map, nregs)
|
||
rtx x;
|
||
rtx *reg_map;
|
||
int nregs;
|
||
{
|
||
register enum rtx_code code;
|
||
register int i;
|
||
register char *fmt;
|
||
|
||
if (x == 0)
|
||
return x;
|
||
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case PC:
|
||
case CC0:
|
||
case CONST_INT:
|
||
case CONST_DOUBLE:
|
||
case CONST:
|
||
case SYMBOL_REF:
|
||
case LABEL_REF:
|
||
return x;
|
||
|
||
case REG:
|
||
/* Verify that the register has an entry before trying to access it. */
|
||
if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0)
|
||
return reg_map[REGNO (x)];
|
||
return x;
|
||
}
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
if (fmt[i] == 'e')
|
||
XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs);
|
||
if (fmt[i] == 'E')
|
||
{
|
||
register int j;
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map, nregs);
|
||
}
|
||
}
|
||
return x;
|
||
}
|
||
|
||
/* Scan X and replace the address of any MEM in it with ADDR.
|
||
REG is the address that MEM should have before the replacement. */
|
||
|
||
static void
|
||
replace_call_address (x, reg, addr)
|
||
rtx x, reg, addr;
|
||
{
|
||
register enum rtx_code code;
|
||
register int i;
|
||
register char *fmt;
|
||
|
||
if (x == 0)
|
||
return;
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case PC:
|
||
case CC0:
|
||
case CONST_INT:
|
||
case CONST_DOUBLE:
|
||
case CONST:
|
||
case SYMBOL_REF:
|
||
case LABEL_REF:
|
||
case REG:
|
||
return;
|
||
|
||
case SET:
|
||
/* Short cut for very common case. */
|
||
replace_call_address (XEXP (x, 1), reg, addr);
|
||
return;
|
||
|
||
case CALL:
|
||
/* Short cut for very common case. */
|
||
replace_call_address (XEXP (x, 0), reg, addr);
|
||
return;
|
||
|
||
case MEM:
|
||
/* If this MEM uses a reg other than the one we expected,
|
||
something is wrong. */
|
||
if (XEXP (x, 0) != reg)
|
||
abort ();
|
||
XEXP (x, 0) = addr;
|
||
return;
|
||
}
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
if (fmt[i] == 'e')
|
||
replace_call_address (XEXP (x, i), reg, addr);
|
||
if (fmt[i] == 'E')
|
||
{
|
||
register int j;
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
replace_call_address (XVECEXP (x, i, j), reg, addr);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Return the number of memory refs to addresses that vary
|
||
in the rtx X. */
|
||
|
||
static int
|
||
count_nonfixed_reads (x)
|
||
rtx x;
|
||
{
|
||
register enum rtx_code code;
|
||
register int i;
|
||
register char *fmt;
|
||
int value;
|
||
|
||
if (x == 0)
|
||
return 0;
|
||
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case PC:
|
||
case CC0:
|
||
case CONST_INT:
|
||
case CONST_DOUBLE:
|
||
case CONST:
|
||
case SYMBOL_REF:
|
||
case LABEL_REF:
|
||
case REG:
|
||
return 0;
|
||
|
||
case MEM:
|
||
return rtx_varies_p (XEXP (x, 0)) + count_nonfixed_reads (XEXP (x, 0));
|
||
}
|
||
|
||
value = 0;
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
if (fmt[i] == 'e')
|
||
value += count_nonfixed_reads (XEXP (x, i));
|
||
if (fmt[i] == 'E')
|
||
{
|
||
register int j;
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
value += count_nonfixed_reads (XVECEXP (x, i, j));
|
||
}
|
||
}
|
||
return value;
|
||
}
|
||
|
||
|
||
#if 0
|
||
/* P is an instruction that sets a register to the result of a ZERO_EXTEND.
|
||
Replace it with an instruction to load just the low bytes
|
||
if the machine supports such an instruction,
|
||
and insert above LOOP_START an instruction to clear the register. */
|
||
|
||
static void
|
||
constant_high_bytes (p, loop_start)
|
||
rtx p, loop_start;
|
||
{
|
||
register rtx new;
|
||
register int insn_code_number;
|
||
|
||
/* Try to change (SET (REG ...) (ZERO_EXTEND (..:B ...)))
|
||
to (SET (STRICT_LOW_PART (SUBREG:B (REG...))) ...). */
|
||
|
||
new = gen_rtx (SET, VOIDmode,
|
||
gen_rtx (STRICT_LOW_PART, VOIDmode,
|
||
gen_rtx (SUBREG, GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)),
|
||
SET_DEST (PATTERN (p)),
|
||
0)),
|
||
XEXP (SET_SRC (PATTERN (p)), 0));
|
||
insn_code_number = recog (new, p);
|
||
|
||
if (insn_code_number)
|
||
{
|
||
register int i;
|
||
|
||
/* Clear destination register before the loop. */
|
||
emit_insn_before (gen_rtx (SET, VOIDmode,
|
||
SET_DEST (PATTERN (p)),
|
||
const0_rtx),
|
||
loop_start);
|
||
|
||
/* Inside the loop, just load the low part. */
|
||
PATTERN (p) = new;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/* Verify that the ostensible loop starting at START
|
||
really is a loop: nothing jumps into it from outside.
|
||
Return the marker for the end of the loop, or zero if not a real loop.
|
||
|
||
Also set the variables `unknown_*_altered' and `loop_has_call',
|
||
and fill in the array `loop_store_addrs'. */
|
||
|
||
static rtx
|
||
verify_loop (f, start)
|
||
rtx f, start;
|
||
{
|
||
register int level = 1;
|
||
register rtx insn, end;
|
||
|
||
/* First find the LOOP_END that matches.
|
||
Also check each insn for storing in memory and record where. */
|
||
|
||
unknown_address_altered = 0;
|
||
unknown_aggregate_altered = 0;
|
||
fixed_aggregate_altered = 0;
|
||
loop_has_call = 0;
|
||
loop_store_addrs_idx = 0;
|
||
|
||
num_mem_sets = 0;
|
||
loops_enclosed = 1;
|
||
loop_continue = 0;
|
||
|
||
for (insn = NEXT_INSN (start); level > 0; insn = NEXT_INSN (insn))
|
||
{
|
||
if (insn == 0)
|
||
/* Parse errors can cause a loop-beg with no loop-end. */
|
||
return 0;
|
||
if (GET_CODE (insn) == NOTE)
|
||
{
|
||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
|
||
{
|
||
++level;
|
||
/* Count number of loops contained in this one. */
|
||
loops_enclosed++;
|
||
}
|
||
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
|
||
{
|
||
--level;
|
||
if (level == 0)
|
||
{
|
||
end = insn;
|
||
break;
|
||
}
|
||
}
|
||
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
|
||
{
|
||
if (level == 1)
|
||
loop_continue = insn;
|
||
}
|
||
|
||
/* Don't optimize loops containing setjmps.
|
||
On some machines, longjmp does not restore the reg
|
||
values as of the time of the setjmp. */
|
||
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
|
||
return 0;
|
||
}
|
||
else if (GET_CODE (insn) == CALL_INSN)
|
||
{
|
||
unknown_address_altered = 1;
|
||
loop_has_call = 1;
|
||
}
|
||
/* ???
|
||
else if (! unknown_address_altered) */
|
||
else
|
||
{
|
||
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
|
||
note_stores (PATTERN (insn), note_addr_stored);
|
||
}
|
||
}
|
||
|
||
/* Now scan all jumps in the function and see if any of them can
|
||
reach a label within the range of the loop. */
|
||
|
||
for (insn = f; insn; insn = NEXT_INSN (insn))
|
||
if (GET_CODE (insn) == JUMP_INSN
|
||
/* Don't get fooled by jumps inserted by loop-optimize.
|
||
They don't have valid LUIDs, and they never jump into loops. */
|
||
&& INSN_UID (insn) < max_uid
|
||
&& (INSN_LUID (insn) < INSN_LUID (start)
|
||
|| INSN_LUID (insn) > INSN_LUID (end))
|
||
/* We have a jump that is outside the loop.
|
||
Does it jump into the loop? */
|
||
&& can_jump_into_range_p (PATTERN (insn),
|
||
INSN_LUID (start), INSN_LUID (end)))
|
||
return 0;
|
||
|
||
#if 0
|
||
/* Now scan all labels between them and check for any jumps from outside.
|
||
This uses the ref-chains set up by find_basic_blocks.
|
||
This code is not used because it's more convenient for other reasons
|
||
to do the loop optimization before find_basic_blocks. */
|
||
|
||
for (insn = start; insn != end; insn = NEXT_INSN (insn))
|
||
if (GET_CODE (insn) == CODE_LABEL)
|
||
{
|
||
register rtx y;
|
||
for (y = LABEL_REFS (insn); y != insn; y = LABEL_NEXTREF (y))
|
||
if (INSN_LUID (CONTAINING_INSN (y)) < INSN_LUID (start)
|
||
|| INSN_LUID (CONTAINING_INSN (y)) > INSN_LUID (end))
|
||
return 0;
|
||
}
|
||
#endif
|
||
|
||
return end;
|
||
}
|
||
|
||
/* Return 1 if somewhere in X is a LABEL_REF to a label
|
||
located between BEG and END. */
|
||
|
||
static int
|
||
can_jump_into_range_p (x, beg, end)
|
||
rtx x;
|
||
int beg, end;
|
||
{
|
||
register enum rtx_code code = GET_CODE (x);
|
||
register int i;
|
||
register char *fmt;
|
||
|
||
if (code == LABEL_REF)
|
||
{
|
||
register int luid = INSN_LUID (XEXP (x, 0));
|
||
return luid > beg && luid < end;
|
||
}
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
if (fmt[i] == 'e')
|
||
{
|
||
if (can_jump_into_range_p (XEXP (x, i), beg, end))
|
||
return 1;
|
||
}
|
||
else if (fmt[i] == 'E')
|
||
{
|
||
register int j;
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
if (can_jump_into_range_p (XVECEXP (x, i, j), beg, end))
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Return nonzero if there is a label in the range from
|
||
insn INSN to the insn whose luid is END. */
|
||
|
||
static int
|
||
labels_in_range_p (insn, end)
|
||
rtx insn;
|
||
int end;
|
||
{
|
||
while (insn && INSN_LUID (insn) <= end)
|
||
{
|
||
if (GET_CODE (insn) == CODE_LABEL)
|
||
return 0;
|
||
insn = NEXT_INSN (insn);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Record that a memory reference X is being set. */
|
||
|
||
static void
|
||
note_addr_stored (x)
|
||
rtx x;
|
||
{
|
||
if (x == 0 || GET_CODE (x) != MEM)
|
||
return;
|
||
|
||
/* Count number of memory writes.
|
||
This affects heuristics in strength_reduce. */
|
||
num_mem_sets++;
|
||
if (unknown_address_altered)
|
||
return;
|
||
|
||
if (GET_MODE (x) == BLKmode)
|
||
unknown_address_altered = 1;
|
||
else if (rtx_addr_varies_p (x))
|
||
{
|
||
if (GET_CODE (XEXP (x, 0)) == PLUS)
|
||
unknown_aggregate_altered = 1;
|
||
else
|
||
unknown_address_altered = 1;
|
||
}
|
||
else
|
||
{
|
||
register int i;
|
||
register rtx addr = XEXP (x, 0);
|
||
|
||
if (MEM_IN_STRUCT_P (x))
|
||
fixed_aggregate_altered = 1;
|
||
for (i = 0; i < loop_store_addrs_idx; i++)
|
||
if (rtx_equal_p (loop_store_addrs[i], addr))
|
||
{
|
||
if (loop_store_widths[i] < GET_MODE_SIZE (GET_MODE (x)))
|
||
loop_store_widths[i] = GET_MODE_SIZE (GET_MODE (x));
|
||
break;
|
||
}
|
||
if (i == NUM_STORES)
|
||
unknown_address_altered = 1;
|
||
else if (i == loop_store_addrs_idx)
|
||
{
|
||
loop_store_widths[i] = GET_MODE_SIZE (GET_MODE (x));
|
||
loop_store_addrs[loop_store_addrs_idx++] = addr;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Return nonzero if the rtx X is invariant over the current loop.
|
||
|
||
The value is 2 if we refer to something only conditionally invariant.
|
||
|
||
If `unknown_address_altered' is nonzero, no memory ref is invariant.
|
||
Otherwise if `unknown_aggregate_altered' is nonzero,
|
||
a memory ref is invariant if it is not part of an aggregate
|
||
and its address is fixed and not in `loop_store_addrs'.
|
||
Otherwise if `fixed_aggregate_altered' is nonzero,
|
||
a memory ref is invariant
|
||
if its address is fixed and not in `loop_store_addrs'.
|
||
Otherwise, a memory ref is invariant if its address is fixed and not in
|
||
`loop_store_addrs' or if it is not an aggregate. */
|
||
|
||
static int
|
||
invariant_p (x)
|
||
register rtx x;
|
||
{
|
||
register int i;
|
||
register enum rtx_code code;
|
||
register char *fmt;
|
||
int conditional = 0;
|
||
|
||
if (x == 0)
|
||
return 1;
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case CONST_INT:
|
||
case CONST_DOUBLE:
|
||
case SYMBOL_REF:
|
||
case LABEL_REF:
|
||
case CONST:
|
||
return 1;
|
||
|
||
case PC:
|
||
case CC0:
|
||
return 0;
|
||
|
||
case REG:
|
||
/* We used to check RTX_UNCHANGING_P (x) here, but that is invalid
|
||
since the reg might be set by initialization within the loop. */
|
||
if (x == frame_pointer_rtx || x == arg_pointer_rtx)
|
||
return 1;
|
||
if (n_times_set[REGNO (x)] == -1)
|
||
return 2;
|
||
return n_times_set[REGNO (x)] == 0;
|
||
|
||
case MEM:
|
||
/* Constants in the constant pool are invariant.
|
||
?? Really we should detect any constant address in the
|
||
text section. */
|
||
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
|
||
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
|
||
return 1;
|
||
/* A store in a varying-address scalar (or a subroutine call)
|
||
could clobber anything in memory. */
|
||
if (unknown_address_altered)
|
||
return 0;
|
||
/* Don't mess with volatile memory references. */
|
||
if (MEM_VOLATILE_P (x))
|
||
return 0;
|
||
#if 0
|
||
/* If it's declared read-only, it is invariant
|
||
if its address is invariant. */
|
||
if (RTX_UNCHANGING_P (x))
|
||
return invariant_p (XEXP (x, 0));
|
||
#endif
|
||
/* A store in a varying-address aggregate component
|
||
could clobber anything except a scalar with a fixed address. */
|
||
if (unknown_aggregate_altered
|
||
&& ((MEM_IN_STRUCT_P (x) || GET_CODE (XEXP (x, 0)) == PLUS)
|
||
|| rtx_addr_varies_p (x)))
|
||
return 0;
|
||
/* A store in a fixed-address aggregate component
|
||
could clobber anything whose address is not fixed,
|
||
even an aggregate component. */
|
||
if (fixed_aggregate_altered
|
||
&& rtx_addr_varies_p (x))
|
||
return 0;
|
||
/* Any store could clobber a varying-address scalar. */
|
||
if (loop_store_addrs_idx
|
||
&& !(MEM_IN_STRUCT_P (x) || GET_CODE (XEXP (x, 0)) == PLUS)
|
||
&& rtx_addr_varies_p (x))
|
||
return 0;
|
||
/* A store in a fixed address clobbers overlapping references. */
|
||
for (i = loop_store_addrs_idx - 1; i >= 0; i--)
|
||
if (addr_overlap_p (x, loop_store_addrs[i], loop_store_widths[i]))
|
||
return 0;
|
||
/* It's not invalidated by a store in memory
|
||
but we must still verify the address is invariant. */
|
||
break;
|
||
|
||
case ASM_OPERANDS:
|
||
/* Don't mess with insns declared volatile. */
|
||
if (MEM_VOLATILE_P (x))
|
||
return 0;
|
||
}
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
if (fmt[i] == 'e')
|
||
{
|
||
int tem = invariant_p (XEXP (x, i));
|
||
if (tem == 0)
|
||
return 0;
|
||
if (tem == 2)
|
||
conditional = 1;
|
||
}
|
||
else if (fmt[i] == 'E')
|
||
{
|
||
register int j;
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
{
|
||
int tem = invariant_p (XVECEXP (x, i, j));
|
||
if (tem == 0)
|
||
return 0;
|
||
if (tem == 2)
|
||
conditional = 1;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
return 1 + conditional;
|
||
}
|
||
|
||
/* Return 1 if OTHER (a mem ref) overlaps the area of memory
|
||
which is SIZE bytes starting at BASE. */
|
||
|
||
int
|
||
addr_overlap_p (other, base, size)
|
||
rtx other;
|
||
rtx base;
|
||
int size;
|
||
{
|
||
int start = 0, end;
|
||
|
||
if (GET_CODE (base) == CONST)
|
||
base = XEXP (base, 0);
|
||
if (GET_CODE (base) == PLUS
|
||
&& GET_CODE (XEXP (base, 1)) == CONST_INT)
|
||
{
|
||
start = INTVAL (XEXP (base, 1));
|
||
base = XEXP (base, 0);
|
||
}
|
||
|
||
end = start + size;
|
||
return refers_to_mem_p (other, base, start, end);
|
||
}
|
||
|
||
/* Return nonzero if all the insns in the loop that set REG
|
||
are INSN and the immediately following insns,
|
||
and if each of those insns sets REG in an invariant way
|
||
(not counting uses of REG in them).
|
||
|
||
The value is 2 if some of these insns are only conditionally invariant.
|
||
|
||
We assume that INSN itself is the first set of REG
|
||
and that its source is invariant. */
|
||
|
||
static int
|
||
consec_sets_invariant_p (reg, n_sets, insn)
|
||
int n_sets;
|
||
rtx reg, insn;
|
||
{
|
||
register rtx p = insn;
|
||
register int regno = REGNO (reg);
|
||
rtx temp;
|
||
/* Number of sets we have to insist on finding after INSN. */
|
||
int count = n_sets - 1;
|
||
int old = n_times_set[regno];
|
||
int value = 0;
|
||
int this;
|
||
|
||
/* If N_SETS hit the limit, we can't rely on its value. */
|
||
if (n_sets == 127)
|
||
return 0;
|
||
|
||
n_times_set[regno] = 0;
|
||
|
||
while (count > 0)
|
||
{
|
||
register enum rtx_code code;
|
||
p = NEXT_INSN (p);
|
||
code = GET_CODE (p);
|
||
|
||
/* If library call, skip to end of of it. */
|
||
if (code == INSN && (temp = find_reg_note (p, REG_LIBCALL, 0)))
|
||
p = XEXP (temp, 0);
|
||
|
||
this = 0;
|
||
if (code == INSN && GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG
|
||
&& REGNO (SET_DEST (PATTERN (p))) == regno)
|
||
{
|
||
this = invariant_p (SET_SRC (PATTERN (p)));
|
||
if (this != 0)
|
||
value |= this;
|
||
else if (temp = find_reg_note (p, REG_EQUAL, 0))
|
||
{
|
||
this = invariant_p (XEXP (temp, 0));
|
||
if (this != 0)
|
||
value |= this;
|
||
}
|
||
}
|
||
if (this != 0)
|
||
count--;
|
||
else if (code != NOTE)
|
||
{
|
||
n_times_set[regno] = old;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
n_times_set[regno] = old;
|
||
/* If invariant_p ever returned 2, we return 2. */
|
||
return 1 + (value & 2);
|
||
}
|
||
|
||
#if 0
|
||
/* I don't think this condition is sufficient to allow INSN
|
||
to be moved, so we no longer test it. */
|
||
|
||
/* Return 1 if all insns in the basic block of INSN and following INSN
|
||
that set REG are invariant according to TABLE. */
|
||
|
||
static int
|
||
all_sets_invariant_p (reg, insn, table)
|
||
rtx reg, insn;
|
||
short *table;
|
||
{
|
||
register rtx p = insn;
|
||
register int regno = REGNO (reg);
|
||
|
||
while (1)
|
||
{
|
||
register enum rtx_code code;
|
||
p = NEXT_INSN (p);
|
||
code = GET_CODE (p);
|
||
if (code == CODE_LABEL || code == JUMP_INSN)
|
||
return 1;
|
||
if (code == INSN && GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG
|
||
&& REGNO (SET_DEST (PATTERN (p))) == regno)
|
||
{
|
||
if (!invariant_p (SET_SRC (PATTERN (p)), table))
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
#endif /* 0 */
|
||
|
||
/* Increment N_TIMES_SET at the index of each register
|
||
that is modified by an insn between FROM and TO.
|
||
If the value of an element of N_TIMES_SET becomes 127 or more,
|
||
stop incrementing it, to avoid overflow.
|
||
|
||
Store in *COUNT_PTR the number of actual instruction
|
||
in the loop. We use this to decide what is worth moving out. */
|
||
|
||
/* last_set[n] is nonzero iff reg n has been set in the current basic block.
|
||
In that case, it is the insn that last set reg n. */
|
||
|
||
static void
|
||
count_loop_regs_set (from, to, may_not_move, count_ptr, nregs)
|
||
register rtx from, to;
|
||
char *may_not_move;
|
||
int *count_ptr;
|
||
int nregs;
|
||
{
|
||
register rtx *last_set = (rtx *) alloca (nregs * sizeof (rtx));
|
||
register rtx insn;
|
||
register int count = 0;
|
||
register rtx dest;
|
||
|
||
bzero (last_set, nregs * sizeof (rtx));
|
||
for (insn = from; insn != to; insn = NEXT_INSN (insn))
|
||
{
|
||
if (GET_CODE (insn) == CALL_INSN)
|
||
{
|
||
/* If a register is used as a subroutine address,
|
||
don't allow this register's setting to be moved out of the loop.
|
||
This condition is not at all logically correct
|
||
but it averts a very common lossage pattern
|
||
and creates lossage much less often. */
|
||
if (GET_CODE (PATTERN (insn)) == CALL
|
||
&& GET_CODE (XEXP (PATTERN (insn), 0)) == MEM
|
||
&& GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == REG)
|
||
{
|
||
register int regno
|
||
= REGNO (XEXP (XEXP (PATTERN (insn), 0), 0));
|
||
may_not_move[regno] = 1;
|
||
}
|
||
else if (GET_CODE (PATTERN (insn)) == SET
|
||
&& GET_CODE (SET_SRC (PATTERN (insn))) == CALL
|
||
&& GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 0)) == MEM
|
||
&& GET_CODE (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0)) == REG)
|
||
{
|
||
register int regno
|
||
= REGNO (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0));
|
||
may_not_move[regno] = 1;
|
||
/* The call insn itself sets a reg, which cannot be moved. */
|
||
may_not_move[REGNO (SET_DEST (PATTERN (insn)))] = 1;
|
||
if (n_times_set[REGNO (SET_DEST (PATTERN (insn)))] < 127)
|
||
n_times_set[REGNO (SET_DEST (PATTERN (insn)))]++;
|
||
}
|
||
}
|
||
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
|
||
{
|
||
++count;
|
||
if (GET_CODE (PATTERN (insn)) == CLOBBER
|
||
&& GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
|
||
/* Don't move a reg that has an explicit clobber.
|
||
We might do so sometimes, but it's not worth the pain. */
|
||
may_not_move[REGNO (XEXP (PATTERN (insn), 0))] = 1;
|
||
else if (GET_CODE (PATTERN (insn)) == SET)
|
||
{
|
||
dest = SET_DEST (PATTERN (insn));
|
||
while (GET_CODE (dest) == SUBREG
|
||
|| GET_CODE (dest) == ZERO_EXTRACT
|
||
|| GET_CODE (dest) == SIGN_EXTRACT
|
||
|| GET_CODE (dest) == STRICT_LOW_PART)
|
||
dest = XEXP (dest, 0);
|
||
if (GET_CODE (dest) == REG)
|
||
{
|
||
register int regno = REGNO (dest);
|
||
/* If this is the first setting of this reg
|
||
in current basic block, and it was set before,
|
||
it must be set in two basic blocks, so it cannot
|
||
be moved out of the loop. */
|
||
if (n_times_set[regno] > 0 && last_set[regno] == 0)
|
||
may_not_move[regno] = 1;
|
||
/* If this is not first setting in current basic block,
|
||
see if reg was used in between previous one and this.
|
||
If so, neither one can be moved. */
|
||
if (last_set[regno] != 0
|
||
&& reg_used_between_p (dest, last_set[regno], insn))
|
||
may_not_move[regno] = 1;
|
||
if (n_times_set[regno] < 127)
|
||
++n_times_set[regno];
|
||
last_set[regno] = insn;
|
||
}
|
||
}
|
||
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
|
||
{
|
||
register int i;
|
||
for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
|
||
{
|
||
register rtx x = XVECEXP (PATTERN (insn), 0, i);
|
||
if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
|
||
/* Don't move a reg that has an explicit clobber.
|
||
It's not worth the pain to try to do it correctly. */
|
||
may_not_move[REGNO (XEXP (x, 0))] = 1;
|
||
if (GET_CODE (x) == SET)
|
||
{
|
||
dest = SET_DEST (x);
|
||
while (GET_CODE (dest) == SUBREG
|
||
|| GET_CODE (dest) == ZERO_EXTRACT
|
||
|| GET_CODE (dest) == SIGN_EXTRACT
|
||
|| GET_CODE (dest) == STRICT_LOW_PART)
|
||
dest = XEXP (dest, 0);
|
||
if (GET_CODE (dest) == REG)
|
||
{
|
||
register int regno = REGNO (dest);
|
||
if (n_times_set[regno] < 127)
|
||
++n_times_set[regno];
|
||
may_not_move[regno] = 1;
|
||
last_set[regno] = insn;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
|
||
bzero (last_set, nregs * sizeof (rtx));
|
||
}
|
||
*count_ptr = count;
|
||
}
|
||
|
||
/* Given a loop that is bounded by LOOP_START and LOOP_END
|
||
and that is entered at SCAN_START,
|
||
return 1 if the register set by insn INSN is used by
|
||
any insn that precedes INSN in cyclic order starting
|
||
from the loop entry point. */
|
||
|
||
static int
|
||
loop_reg_used_before_p (insn, loop_start, scan_start, loop_end)
|
||
rtx insn, loop_start, scan_start, loop_end;
|
||
{
|
||
rtx reg = SET_DEST (PATTERN (insn));
|
||
if (INSN_LUID (scan_start) > INSN_LUID (insn))
|
||
return (reg_used_between_p (reg, scan_start, loop_end)
|
||
|| reg_used_between_p (reg, loop_start, insn));
|
||
else
|
||
return reg_used_between_p (reg, scan_start, insn);
|
||
}
|
||
|
||
/* A "basic induction variable" or biv is a pseudo reg that is set
|
||
(within this loop) only by incrementing or decrementing it. */
|
||
/* A "general induction variable" or giv is a pseudo reg whose
|
||
value is a linear function of a biv. */
|
||
|
||
/* Bivs are recognized by `basic_induction_var';
|
||
Givs by `general_induct_var'. */
|
||
|
||
/* An enum for the two different types of givs, those that are used
|
||
as memory addresses and those that are calculated into registers. */
|
||
enum g_types { DEST_ADDR, DEST_REG };
|
||
|
||
/* A `struct induction' is created for every instruction that sets
|
||
an induction variable (either a biv or a giv). */
|
||
|
||
struct induction
|
||
{
|
||
rtx insn; /* The insn that sets a biv or giv */
|
||
rtx new_reg; /* New register, containing strength reduced
|
||
version of this giv. */
|
||
int src_regno; /* Biv from which this giv is computed.
|
||
(If this is a biv, then this is the biv.) */
|
||
enum g_types giv_type; /* Indicate whether DEST_ADDR or DEST_REG giv */
|
||
int dest_regno; /* Destination register for insn: this is the
|
||
register which was the biv or giv.
|
||
For a biv, this equals src_reg.
|
||
For a DEST_ADDR type giv, this is 0. */
|
||
rtx *location; /* Place in the insn where this giv occurs.
|
||
If GIV_TYPE is DEST_REG, this is 0. */
|
||
enum machine_mode mode; /* The mode of this biv or giv */
|
||
rtx mult_val; /* Multiplicative factor for src_reg. */
|
||
rtx add_val; /* Additive constant for that product. */
|
||
int benefit; /* Gain from eliminating this insn. */
|
||
int consec; /* The number of consecutive insn that set this
|
||
register; they are all eliminated if this
|
||
one is. */
|
||
char replaceable; /* 1 if we can substitute the strength-reduced
|
||
variable for the original variable.
|
||
0 means they must be kept separate and the
|
||
new one must be copied into the old pseudo
|
||
reg each time the old one is set. */
|
||
char ignore; /* 1 prohibits further processing of this giv */
|
||
int lifetime; /* Length of life of this giv */
|
||
int times_used; /* # times this giv is used. */
|
||
struct induction *family; /* Links together all induction variables that
|
||
have the same src register. */
|
||
struct induction *forces; /* Points to an induction variable insn which
|
||
is used only once, to compute this giv,
|
||
and hence can be deleted if this insn is
|
||
strength reduced. */
|
||
struct induction *forces2; /* Likewise. */
|
||
struct induction *same; /* Links together all induction variables that
|
||
have the same tuple (src, mult, add). */
|
||
};
|
||
|
||
/* A `struct iv_class' is created for each biv. */
|
||
|
||
struct iv_class {
|
||
int regno; /* Pseudo reg which is the biv. */
|
||
int biv_count; /* Number of insns setting this reg. */
|
||
struct induction *biv; /* List of all insns that set this reg. */
|
||
int giv_count; /* Number of DEST_REG givs computed from this
|
||
biv. The resulting count is only used in
|
||
check_dbra_loop. */
|
||
struct induction *giv; /* List of all insns that compute a giv
|
||
from this reg. */
|
||
int total_benefit; /* Sum of BENEFITs of all those givs */
|
||
rtx initial_value; /* Value of reg at loop start */
|
||
struct iv_class *next; /* Links all class structures together */
|
||
rtx init_insn; /* insn which intializes biv, 0 if none seen. */
|
||
char eliminable; /* 1 if plausible candidate for elimination. */
|
||
char nonneg; /* 1 if we added a REG_NONNEG note for this. */
|
||
};
|
||
|
||
/* Definitions used by the basic induction variable discovery code. */
|
||
enum iv_mode { UNKNOWN_INDUCT, BASIC_INDUCT, NOT_BASIC_INDUCT,
|
||
GENERAL_INDUCT };
|
||
|
||
/* Relative gain of eliminating various kinds of operations. */
|
||
#define NO_BENEFIT 0
|
||
#define ADD_BENEFIT 1
|
||
#define SHIFT_BENEFIT 2
|
||
#define MULT_BENEFIT 4
|
||
#define LIBCALL_BENEFIT 15
|
||
/* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
|
||
copy the value of the strength reduced giv to its original register. */
|
||
#define COPY_PENALTY 2
|
||
|
||
/* Indexed by register number, indicates whether or not register is an
|
||
induction variable, and if so what type. */
|
||
|
||
static enum iv_mode *induct_var;
|
||
|
||
/* Indexed by register number, contains pointer to `struct induction'
|
||
if register is a general induction variable. */
|
||
|
||
static struct induction **induct_struct;
|
||
|
||
/* Indexed by register number, contains pointer to `struct iv_class'
|
||
if register is a basic induction variable. */
|
||
|
||
static struct iv_class **class_struct;
|
||
|
||
/*********************************/
|
||
|
||
/* ??? Unfinished optimizations, wilson@ji.Berkeley.EDU */
|
||
|
||
/* strength reduce addresses found in sources (set () (mem ())*/
|
||
|
||
/* There is one more optimization you might be interested in doing: to
|
||
allocate pseudo registers for frequently-accessed memory locations.
|
||
If the same memory location is referenced each time around, it might
|
||
be possible to copy it into a register before and out after.
|
||
This is especially useful when the memory location is a variable which
|
||
is in a stack slot because somewhere its address is taken. If the
|
||
loop doesn't contain a function call and the variable isn't volatile,
|
||
it is safe to keep the value in a register for the duration of the
|
||
loop. One tricky thing is that the copying of the value back from the
|
||
register has to be done on all exits from the loop. You need to check that
|
||
all the exits from the loop go to the same place. */
|
||
|
||
/* WARNING: the interaction of biv elimination, and recognizing 'constant'
|
||
bivs may cause problems */
|
||
|
||
/* add heuristic so that DEST_ADDR strength reduction does not cause
|
||
performance problems */
|
||
|
||
/* don't eliminate things that can be combined with an addressing mode?
|
||
find all giv that have same biv and mult_val (now must also have
|
||
same add_val), then for each giv, check to see if its only use
|
||
dies in a following memory address, generate a new memory address
|
||
and check to see if valid, if valid then store modified mem addr,
|
||
else if not valid addr mark giv as not done so that it will get its
|
||
own iv */
|
||
|
||
/* consec_sets_giv does not calculate replaceable and forces correctly,
|
||
forces should be a more general linked list instead of two entries */
|
||
|
||
/* try to optimize branches when it is known that a biv is always positive */
|
||
|
||
/* when replace biv in compare insn, should replace with closest giv so that
|
||
an optimized branch can still be recognized by combiner, i.e. VAXen acb */
|
||
|
||
/* should merge final_value calculation in check_dbra_loop with the
|
||
new final_biv_value function */
|
||
|
||
/* many of the checks involving uid_luid could be simplified if regscan
|
||
was rerun in loop_optimize() whenever a register was added or moved,
|
||
also some of the optimizations could be a little less conservative */
|
||
|
||
/* Perform strength reduction and induction variable elimination. */
|
||
|
||
/* Pseudo registers created during this function will be beyond the last
|
||
valid index in several tables including n_times_set and regno_last_uid.
|
||
This does not cause a problem here, because the added registers cannot be
|
||
givs outside of their loop, and hence will never be reconsidered.
|
||
But scan_loop must check regnos to make sure they are in bounds. */
|
||
|
||
static void
|
||
strength_reduce (scan_start, end, loop_top, insn_count,
|
||
loop_start, loop_end, nregs)
|
||
rtx scan_start;
|
||
rtx end;
|
||
rtx loop_top;
|
||
int insn_count;
|
||
rtx loop_start;
|
||
rtx loop_end;
|
||
int nregs;
|
||
{
|
||
rtx p;
|
||
rtx inc_val;
|
||
rtx mult_val;
|
||
int dest_regno;
|
||
int biv_found;
|
||
/* This is 1 if current insn could be executed zero times in the loop. */
|
||
int maybe_never = 0;
|
||
/* List of all possible basic induction variables. */
|
||
struct iv_class *iv_list = 0;
|
||
/* Temporary list pointers for traversing iv_list. */
|
||
struct iv_class *bl, *backbl;
|
||
/* Ratio of extra register life span we can justify
|
||
for saving an instruction. More if loop doesn't call subroutines
|
||
since in that case saving an insn makes more difference
|
||
and more registers are available. */
|
||
/* ??? could set this to last value of threshold in move_movables */
|
||
int threshold = loop_has_call ? 17 : 34;
|
||
/* Map of pseudo-register replacements. */
|
||
rtx *reg_map;
|
||
int call_seen;
|
||
|
||
induct_var = (enum iv_mode *) alloca (nregs * sizeof (induct_var[0]));
|
||
bzero ((char *)induct_var, nregs * sizeof (induct_var[0]));
|
||
induct_struct = (struct induction **)
|
||
alloca (nregs * sizeof (struct induction *));
|
||
bzero ((char *)induct_struct, nregs * sizeof (struct induction *));
|
||
class_struct = (struct iv_class **)
|
||
alloca (nregs * sizeof (struct iv_class *));
|
||
bzero ((char *)class_struct, nregs * sizeof (struct iv_class *));
|
||
|
||
/* Scan through loop to find all possible bivs. */
|
||
|
||
for (p = NEXT_INSN (loop_start); p != end; p = NEXT_INSN (p))
|
||
{
|
||
if (GET_CODE (p) == INSN
|
||
&& GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG)
|
||
{
|
||
dest_regno = REGNO (SET_DEST (PATTERN (p)));
|
||
if (induct_var[dest_regno] != NOT_BASIC_INDUCT
|
||
&& dest_regno >= FIRST_PSEUDO_REGISTER)
|
||
{
|
||
if (basic_induction_var (SET_SRC (PATTERN (p)), dest_regno,
|
||
&inc_val, &mult_val))
|
||
{
|
||
/* It is a possible basic induction variable.
|
||
Create and initialize an induction structure for it. */
|
||
|
||
struct induction *v =
|
||
(struct induction *) alloca (sizeof (struct induction));
|
||
|
||
v->insn = p;
|
||
v->src_regno = dest_regno;
|
||
v->dest_regno = dest_regno;
|
||
v->mult_val = mult_val;
|
||
v->add_val = inc_val;
|
||
v->mode = GET_MODE (SET_DEST (PATTERN (p)));
|
||
|
||
/* Add this to the reg's iv_class, creating a class
|
||
if this is the first incrementation of the reg. */
|
||
|
||
bl = class_struct[dest_regno];
|
||
if (bl)
|
||
{
|
||
v->family = bl->biv;
|
||
bl->biv = v;
|
||
bl->biv_count++;
|
||
}
|
||
else
|
||
{
|
||
/* Create and initialize new iv_class. */
|
||
|
||
bl = (struct iv_class *) alloca (sizeof (struct iv_class));
|
||
|
||
bl->regno = dest_regno;
|
||
bl->biv = v;
|
||
v->family = 0;
|
||
bl->giv = 0;
|
||
bl->biv_count = 1;
|
||
bl->giv_count = 0;
|
||
|
||
/* Set initial value to the reg itself. */
|
||
bl->initial_value = SET_DEST (PATTERN (p));
|
||
/* We haven't seen the intializing insn yet */
|
||
bl->init_insn = 0;
|
||
bl->eliminable = 0;
|
||
bl->nonneg = 0;
|
||
|
||
/* Add this insn to iv_list. */
|
||
bl->next = iv_list;
|
||
iv_list = bl;
|
||
|
||
/* Put it in the array of iv_lists. */
|
||
class_struct[dest_regno] = bl;
|
||
}
|
||
|
||
induct_var[dest_regno] = BASIC_INDUCT;
|
||
|
||
if (loop_dump_stream)
|
||
{
|
||
fprintf (loop_dump_stream,
|
||
"Insn %d: possible biv, reg %d,",
|
||
INSN_UID (p), dest_regno);
|
||
if (GET_CODE (inc_val) == CONST_INT)
|
||
fprintf (loop_dump_stream, " const = %d\n",
|
||
INTVAL (inc_val));
|
||
else
|
||
{
|
||
fprintf (loop_dump_stream, " const = ");
|
||
print_rtl (loop_dump_stream, inc_val);
|
||
fprintf (loop_dump_stream, "\n");
|
||
}
|
||
}
|
||
}
|
||
else
|
||
induct_var[dest_regno] = NOT_BASIC_INDUCT;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Scan iv_list to remove all regs that proved not to be bivs.
|
||
Make a sanity check against n_times_set. */
|
||
|
||
biv_found = 0;
|
||
|
||
for (backbl = bl = iv_list; bl; backbl = bl, bl = bl->next)
|
||
{
|
||
if (induct_var[bl->regno] != BASIC_INDUCT)
|
||
{
|
||
/* Not a basic induction variable, remove this iv_class. */
|
||
|
||
if (backbl == bl)
|
||
iv_list = bl->next;
|
||
else
|
||
backbl->next = bl->next;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Reg %d: biv discarded, not induct\n",
|
||
bl->regno);
|
||
}
|
||
else if (n_times_set[bl->regno] != bl->biv_count)
|
||
{
|
||
/* This happens if register modified by subreg, etc. */
|
||
/* Make sure it is not recognized as a basic induction var: */
|
||
/* remove this iv_class from iv_list. */
|
||
|
||
induct_var[bl->regno] = NOT_BASIC_INDUCT;
|
||
|
||
if (backbl == bl)
|
||
iv_list = bl->next;
|
||
else
|
||
backbl->next = bl->next;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Reg %d: biv discarded, count error\n",
|
||
bl->regno);
|
||
}
|
||
else
|
||
{
|
||
/* This is a valid basic induction variable. */
|
||
|
||
biv_found++;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Reg %d: biv verified\n", bl->regno);
|
||
}
|
||
}
|
||
|
||
/* Exit if there are no bivs. */
|
||
if (!iv_list)
|
||
return;
|
||
|
||
/* Find initial value for each biv. */
|
||
/* Search backwards from loop_start, halting at first label
|
||
or when all bivs have been seen. */
|
||
|
||
call_seen = 0;
|
||
p = loop_start;
|
||
while (biv_found)
|
||
{
|
||
p = PREV_INSN (p);
|
||
if (p == 0)
|
||
break;
|
||
|
||
if (GET_CODE (p) == CALL_INSN)
|
||
call_seen = 1;
|
||
|
||
if (GET_CODE (p) == INSN
|
||
&& GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG)
|
||
{
|
||
int dest_regno = REGNO (SET_DEST (PATTERN (p)));
|
||
|
||
if (induct_var[dest_regno] == BASIC_INDUCT
|
||
&& class_struct[dest_regno]->init_insn == 0)
|
||
{
|
||
/* This is the first modification found for this reg. */
|
||
|
||
rtx src = SET_SRC (PATTERN (p));
|
||
|
||
/* Record the intializing INSN */
|
||
|
||
class_struct[dest_regno]->init_insn = p;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Biv %d initialized at insn %d: ",
|
||
dest_regno, INSN_UID (p));
|
||
|
||
/* Save value if it is a constant or register. */
|
||
if (CONSTANT_P (src)
|
||
|| (GET_CODE (src) == REG
|
||
/* Don't try to use a value in a hard reg
|
||
across a call which clobbers it. */
|
||
&& ! (REGNO (src) < FIRST_PSEUDO_REGISTER
|
||
&& call_used_regs[REGNO (src)]
|
||
&& call_seen)
|
||
&& ! reg_set_between_p (src, p, loop_start)))
|
||
{
|
||
class_struct[dest_regno]->initial_value = src;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "initial value ");
|
||
if (loop_dump_stream)
|
||
{
|
||
if (GET_CODE (src) == CONST_INT)
|
||
fprintf (loop_dump_stream, "%d\n", INTVAL (src));
|
||
else
|
||
{
|
||
print_rtl (loop_dump_stream, src);
|
||
fprintf (loop_dump_stream, "\n");
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Biv initial value is not simple move,
|
||
so let it keep intial value of "itself". */
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "complex initial value\n");
|
||
}
|
||
|
||
biv_found--;
|
||
}
|
||
}
|
||
else if (GET_CODE (p) == CODE_LABEL)
|
||
break;
|
||
}
|
||
|
||
/* Search the loop for general induction variables. */
|
||
|
||
/* A register is a giv if: it is only set once, it is a function of a
|
||
biv and a constant (or invariant), and it is not a biv. */
|
||
|
||
p = scan_start;
|
||
while (1)
|
||
{
|
||
p = NEXT_INSN (p);
|
||
/* At end of a straight-in loop, we are done.
|
||
At end of a loop entered at the bottom, scan the top. */
|
||
if (p == scan_start)
|
||
break;
|
||
if (p == end)
|
||
{
|
||
if (loop_top != 0)
|
||
p = NEXT_INSN (loop_top);
|
||
else
|
||
break;
|
||
if (p == scan_start)
|
||
break;
|
||
}
|
||
|
||
/* Look for a general induction variable in a register. */
|
||
if (GET_CODE (p) == INSN
|
||
&& GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG)
|
||
{
|
||
int src_regno;
|
||
rtx add_val;
|
||
rtx mult_val;
|
||
int benefit;
|
||
rtx regnote = 0;
|
||
struct induction *forces = 0;
|
||
struct induction *forces2 = 0;
|
||
|
||
dest_regno = REGNO (SET_DEST (PATTERN (p)));
|
||
if (dest_regno < FIRST_PSEUDO_REGISTER)
|
||
continue;
|
||
|
||
if (/* Normal giv. */
|
||
((benefit = general_induction_var (SET_SRC (PATTERN (p)),
|
||
&src_regno, &add_val,
|
||
&mult_val,
|
||
&forces, &forces2))
|
||
/* Giv set with call to a library routine. */
|
||
|| ((regnote = find_reg_note (p, REG_EQUAL, 0))
|
||
&&
|
||
(benefit = general_induction_var (XEXP (regnote, 0),
|
||
&src_regno,
|
||
&add_val, &mult_val,
|
||
&forces, &forces2))))
|
||
/* Don't try to handle any regs made by loop optimization.
|
||
We have nothing on them in regno_first_uid, etc. */
|
||
&& dest_regno < old_max_reg
|
||
/* Don't recognize a BASIC_INDUCT_VAR here. */
|
||
&& dest_regno != src_regno
|
||
/* This must be the only place where the register is set. */
|
||
&& (n_times_set[dest_regno] == 1
|
||
|| (benefit = consec_sets_giv (benefit, p,
|
||
src_regno, dest_regno,
|
||
&add_val, &mult_val))))
|
||
{
|
||
int count;
|
||
struct induction *v =
|
||
(struct induction *) alloca (sizeof (struct induction));
|
||
rtx temp;
|
||
|
||
record_giv (v, p, src_regno, dest_regno, mult_val, add_val, benefit,
|
||
forces, forces2, DEST_REG, maybe_never, 0, loop_end);
|
||
|
||
/* Skip the consecutive insns, if there are any. */
|
||
for (count = v->consec - 1; count >= 0; count--)
|
||
{
|
||
/* If first insn of libcall sequence, skip to end. */
|
||
/* Do this at start of loop, since INSN is guaranteed to
|
||
be an insn here. */
|
||
if (temp = find_reg_note (p, REG_LIBCALL, 0))
|
||
{
|
||
/* Eliminating a libcall does more good than
|
||
eliminating a single insn to do the same job. */
|
||
benefit += LIBCALL_BENEFIT;
|
||
p = XEXP (temp, 0);
|
||
}
|
||
|
||
do p = NEXT_INSN (p);
|
||
while (GET_CODE (p) == NOTE);
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifndef DONT_REDUCE_ADDR
|
||
/* Look for givs which are memory addresses. */
|
||
/* This resulted in worse code on a VAX 8600. I wonder if it
|
||
still does. */
|
||
if (GET_CODE (p) == INSN)
|
||
find_mem_givs (PATTERN (p), p, maybe_never, loop_end);
|
||
#endif
|
||
|
||
/* Past a label or a jump, we get to insns for which we can't count
|
||
on whether or how many times they will be executed during each
|
||
iteration. Givs found afterwards cannot be marked replaceable. */
|
||
if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
|
||
maybe_never = 1;
|
||
}
|
||
|
||
/* Try to prove that the loop counter variable (if any) is always
|
||
nonnegative; if so, record that fact with a REG_NONNEG note
|
||
so that "decrement and branch until zero" insn can be used. */
|
||
check_dbra_loop (loop_end, iv_list, insn_count, loop_start);
|
||
|
||
/* Create reg_map to hold substitutions for replaceable giv regs. */
|
||
reg_map = (rtx *) alloca (nregs * sizeof (rtx));
|
||
bzero ((char *)reg_map, nregs * sizeof (rtx));
|
||
|
||
/* Examine each iv class for feasibility of strength reduction/induction
|
||
variable elimination. */
|
||
|
||
for (bl = iv_list; bl; bl = bl->next)
|
||
{
|
||
struct induction *v;
|
||
int benefit;
|
||
int replaceable;
|
||
int all_reduced;
|
||
rtx final_value = 0;
|
||
|
||
/* Test whether it will be possible to eliminate this biv
|
||
provided all givs are reduced. This is possible if either
|
||
the reg is not used outside the loop, or we can compute
|
||
what its final value will be.
|
||
|
||
Don't try if we put a REG_NONNEG note on the endtest for this biv.
|
||
??? That should be only on machines that have dbra insns. */
|
||
|
||
/* Compare against bl->init_insn rather than loop_start.
|
||
We aren't concerned with any uses of the biv between
|
||
init_insn and loop_start since these won't be affected
|
||
by the value of the biv elsewhere in the function, so
|
||
long as init_insn doesn't use the biv itself.
|
||
March 14, 1989 -- self@bayes.arc.nasa.gov */
|
||
|
||
if ((uid_luid[regno_last_uid[bl->regno]] < INSN_LUID (loop_end)
|
||
&& bl->init_insn
|
||
&& uid_luid[regno_first_uid[bl->regno]] >= INSN_LUID (bl->init_insn)
|
||
&& ! reg_mentioned_p (SET_DEST (PATTERN (bl->biv->insn)),
|
||
SET_SRC (PATTERN (bl->init_insn)))
|
||
&& ! bl->nonneg)
|
||
|| (final_value = final_biv_value (bl, loop_end)))
|
||
check_eliminate_biv (bl, loop_start, end);
|
||
else
|
||
{
|
||
if (loop_dump_stream)
|
||
{
|
||
fprintf (loop_dump_stream,
|
||
"Cannot eliminate biv %d.\n",
|
||
bl->regno);
|
||
fprintf (loop_dump_stream,
|
||
"First use: insn %d, last use: insn %d.\n",
|
||
regno_first_uid[bl->regno],
|
||
regno_last_uid[bl->regno]);
|
||
}
|
||
}
|
||
|
||
/* This will be true at the end, if all givs which depend on this
|
||
biv have been strength reduced.
|
||
We can't (currently) eliminate the biv unless this is so. */
|
||
all_reduced = 1;
|
||
|
||
/* Check each giv in this class. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
{
|
||
struct induction *tv;
|
||
|
||
if (v->ignore)
|
||
continue;
|
||
|
||
benefit = v->benefit;
|
||
replaceable = v->replaceable;
|
||
|
||
/* Reduce benefit if not replaceable, since we will insert
|
||
a move-insn to replace the insn that calculates this giv. */
|
||
if (!replaceable && ! bl->eliminable)
|
||
benefit -= COPY_PENALTY;
|
||
|
||
/* Decrease the benefit to count the add-insns that we will
|
||
insert to increment the reduced reg for the giv. */
|
||
benefit -= ADD_BENEFIT * bl->biv_count;
|
||
|
||
/* Find all equivalent givs (that bear same relation to the biv).
|
||
Link them via the `same' field and add their benefits together.
|
||
They can be replaced with a single register. */
|
||
|
||
for (tv = v->family; tv; tv = tv->family)
|
||
{
|
||
if (tv->ignore == 0
|
||
&& tv->src_regno == v->src_regno
|
||
&& rtx_equal_p (tv->mult_val, v->mult_val)
|
||
&& rtx_equal_p (tv->add_val, v->add_val))
|
||
{
|
||
benefit += tv->benefit;
|
||
if (! tv->replaceable)
|
||
benefit -= COPY_PENALTY;
|
||
v->lifetime += tv->lifetime;
|
||
v->times_used += tv->times_used;
|
||
tv->ignore = 1;
|
||
|
||
/* Link them together via `same' field. */
|
||
tv->same = v->same;
|
||
v->same = tv;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream,
|
||
"giv of insn %d combined with that of %d.\n",
|
||
INSN_UID (v->insn), INSN_UID (tv->insn));
|
||
}
|
||
}
|
||
|
||
/* Decide whether to strength-reduce this giv
|
||
or to leave the code unchanged
|
||
(recompute it from the biv each time it is used).
|
||
This decision can be made independently for each giv. */
|
||
|
||
/* ??? Perhaps attempt to guess whether autoincrement will handle
|
||
some of the new add insns; if so, can increase BENEFIT
|
||
(undo the subtraction of ADD_BENEFIT that was done above). */
|
||
|
||
/* If an insn is not to be strength reduced, then set its ignore
|
||
flag, and clear all_reduced. */
|
||
|
||
/* Is it right to consider times_used? */
|
||
|
||
/* ??? What about the insns that are 'forced' by this one?
|
||
Although this insn is not worthwhile to reduce, it may be
|
||
worthwhile to reduce the simpler givs used to compute this
|
||
complex giv. */
|
||
|
||
/* ??? Hey! If a giv has its forces field set, then that means
|
||
it is not computed directly from the biv, it is instead computed
|
||
from a simpler giv. If we define UNFORCE_INSNS, then the simpler
|
||
giv will be considered for strength reduction, and this giv should
|
||
not cause all_reduced to be cleared because it DOESN'T use the
|
||
biv!!! If the simpler giv can not be reduced, then that simpler
|
||
biv will still cause all_reduced to be cleared. */
|
||
|
||
if (benefit <= 0)
|
||
{
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "giv of insn %d, no benefit\n",
|
||
INSN_UID (v->insn));
|
||
v->ignore = 1;
|
||
all_reduced = 0;
|
||
}
|
||
|
||
if (v->lifetime * threshold * benefit < insn_count)
|
||
{
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream,
|
||
"giv of insn %d not worth while, %d vs %d.\n",
|
||
INSN_UID (v->insn),
|
||
v->lifetime * threshold * benefit, insn_count);
|
||
v->ignore = 1;
|
||
all_reduced = 0;
|
||
}
|
||
|
||
/* Now check that we can increment the reduced giv
|
||
without needing a multiply insn. If not, reject it. */
|
||
|
||
if (! v->ignore)
|
||
{
|
||
int success = 1;
|
||
|
||
for (tv = bl->biv; tv; tv = tv->family)
|
||
if (tv->mult_val == const1_rtx)
|
||
success &= product_cheap_p (tv->add_val, v->mult_val);
|
||
|
||
if (! success)
|
||
{
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream,
|
||
"giv of insn %d: would need a multiply.\n",
|
||
INSN_UID (v->insn));
|
||
v->ignore = 1;
|
||
all_reduced = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Reduce each giv that we decided to reduce. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
{
|
||
struct induction *tv;
|
||
if (! v->ignore)
|
||
{
|
||
rtx new_reg;
|
||
|
||
/* Note Iris compiler dies if ?: is used inside gen_reg_rtx. */
|
||
if (v->giv_type == DEST_ADDR)
|
||
new_reg = gen_reg_rtx (Pmode);
|
||
else
|
||
new_reg = gen_reg_rtx (GET_MODE (SET_DEST (PATTERN (v->insn))));
|
||
|
||
/* For each place where the biv is incremented,
|
||
add an insn to increment the new, reduced reg for the giv.
|
||
Insert it before the insn that sets the biv,
|
||
so that the biv increment remains last before the endtest,
|
||
so that dbra will still be recognized. */
|
||
|
||
for (tv = bl->biv; tv; tv = tv->family)
|
||
{
|
||
struct induction *iv;
|
||
rtx before_insn = tv->insn;
|
||
|
||
/* If this increment is between the setting of the giv and
|
||
its use, don't increment until after the use. */
|
||
for (iv = v; iv; iv = iv->same)
|
||
{
|
||
if (INSN_LUID (tv->insn) <= INSN_LUID (iv->insn)
|
||
&& ((iv->forces
|
||
&& (INSN_LUID (tv->insn)
|
||
>= INSN_LUID (iv->forces->insn))
|
||
|| (iv->forces2
|
||
&& (INSN_LUID (tv->insn)
|
||
>= INSN_LUID (iv->forces2->insn))))))
|
||
{
|
||
before_insn = NEXT_INSN (iv->insn);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (tv->mult_val == const1_rtx)
|
||
emit_iv_inc (tv->add_val, v->mult_val,
|
||
new_reg, before_insn);
|
||
else /* tv->mult_val == const0_rtx */
|
||
/* A multiply is acceptable here
|
||
since this is presumed to be seldom executed. */
|
||
emit_iv_init_code (tv->add_val, v->mult_val,
|
||
v->add_val, new_reg, before_insn);
|
||
}
|
||
|
||
/* Add code at loop start to initialize giv's reduced reg. */
|
||
|
||
emit_iv_init_code (bl->initial_value, v->mult_val,
|
||
v->add_val, new_reg, loop_start);
|
||
|
||
/* For each giv register that can be reduced now:
|
||
delete old insn that modifies the giv,
|
||
if replaceable, substitute reduced reg
|
||
wherever the old giv occurs;
|
||
else add new move insn "giv_reg = reduced_reg". */
|
||
|
||
for (tv = v; tv; tv = tv->same)
|
||
{
|
||
/* Record the identity of the reduced reg. */
|
||
tv->new_reg = new_reg;
|
||
|
||
if (tv->giv_type == DEST_ADDR)
|
||
{
|
||
/* Store reduced reg as the address in the memref
|
||
where we found this giv. */
|
||
* tv->location = new_reg;
|
||
}
|
||
else if (tv->replaceable)
|
||
{
|
||
reg_map[tv->dest_regno] = new_reg;
|
||
/* If giv lives after end of loop,
|
||
emit insn to copy reduced reg into old reg,
|
||
at the end of the loop.
|
||
?? insufficient; used before loop could
|
||
mean live after loop, due to surrounding loop. */
|
||
/* Currently a giv used outside
|
||
the loop will not be marked replaceable,
|
||
so these deficiencies don't really hurt. */
|
||
if (uid_luid[regno_last_uid[tv->dest_regno]]
|
||
> uid_luid[INSN_UID (loop_end)])
|
||
{
|
||
/* ?? This won't work. We need to do this at
|
||
ALL exits. */
|
||
emit_insn_after (gen_rtx (SET, VOIDmode,
|
||
SET_DEST (PATTERN (tv->insn)),
|
||
new_reg),
|
||
loop_end);
|
||
abort ();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Not replaceable; emit an insn to set the
|
||
original giv reg from the reduced giv. */
|
||
|
||
int count;
|
||
rtx after_insn = tv->insn;
|
||
|
||
for (count = tv->consec; count > 0; count--)
|
||
after_insn = next_real_insn (after_insn);
|
||
|
||
/* Put new insn after, not before, in case
|
||
after_insn is the end of a libcall. */
|
||
emit_insn_after (gen_rtx (SET, VOIDmode,
|
||
SET_DEST (PATTERN (tv->insn)),
|
||
new_reg),
|
||
after_insn);
|
||
}
|
||
|
||
/* Delete the insn that used to set the old giv reg,
|
||
unless we modified an address in it.
|
||
In any case, delete the other insns used for this one. */
|
||
delete_insn_forces (tv, tv->giv_type != DEST_ADDR);
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "giv at %d reduced to reg %d\n",
|
||
INSN_UID (tv->insn), REGNO (new_reg));
|
||
}
|
||
/* One set of equivalent givs has been strength-reduced. */
|
||
}
|
||
#if 0
|
||
else if (v->new_reg == 0)
|
||
{
|
||
/* This giv wasn't reduced and is not worth reducing. */
|
||
|
||
for (tv = v; tv; tv = tv->same)
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "giv at %d not reduced\n",
|
||
INSN_UID (tv->insn));
|
||
|
||
all_reduced = 0;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/* All the givs in this family have been reduced if they merit it. */
|
||
|
||
/* Try to eliminate the biv, if it is a candidate.
|
||
This won't work if ! all_reduced,
|
||
since the givs we planned to use might not have been reduced. */
|
||
|
||
if (all_reduced == 1 && bl->eliminable)
|
||
{
|
||
/* Get the REG rtx for the biv. */
|
||
rtx reg = SET_DEST (PATTERN (bl->biv->insn));
|
||
|
||
for (p = loop_start; p != end; p = NEXT_INSN (p))
|
||
{
|
||
enum rtx_code code = GET_CODE (p);
|
||
if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
|
||
&& reg_mentioned_p (reg, PATTERN (p))
|
||
&& SET_DEST (PATTERN (p)) == cc0_rtx)
|
||
/* Found a compare instruction using this biv;
|
||
rewrite it to use a related giv. */
|
||
eliminate_biv (p, bl, loop_start);
|
||
}
|
||
|
||
/* Biv is no longer really needed inside the loop,
|
||
so delete all insns that set the biv. */
|
||
|
||
for (v = bl->biv; v; v = v->family)
|
||
delete_insn (v->insn);
|
||
|
||
/* ?? If we created a new test to bypass the loop entirely,
|
||
or otherwise drop straight in, based on this test, then
|
||
we might want to rewrite it also. This way some later
|
||
pass has more hope of removing the intialization of this
|
||
biv entirely. */
|
||
|
||
/* If final_value != 0, then biv may be used after loop end
|
||
and we must emit an insn to set it just in case. */
|
||
if (final_value != 0)
|
||
emit_insn_after (gen_rtx (SET, VOIDmode, reg, final_value),
|
||
loop_end);
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
|
||
bl->regno);
|
||
}
|
||
}
|
||
|
||
/* Go through all the instructions in the loop, making all the
|
||
register substitutions scheduled in REG_MAP. */
|
||
|
||
for (p = loop_start; p != end; p = NEXT_INSN (p))
|
||
if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
|
||
|| GET_CODE (p) == CALL_INSN)
|
||
replace_regs (PATTERN (p), reg_map, nregs);
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "\n");
|
||
}
|
||
|
||
/* Nonzero if register REG appears somewhere within IN, except in
|
||
subexpressions EQ to EXPR. This is a modification of reg_mentioned_p. */
|
||
|
||
int
|
||
only_reg_use_p (reg, expr, in)
|
||
register rtx reg, expr, in;
|
||
{
|
||
register char *fmt;
|
||
register int i;
|
||
register enum rtx_code code;
|
||
|
||
if (in == 0)
|
||
return 0;
|
||
|
||
if (reg == expr)
|
||
return 0;
|
||
|
||
if (reg == in)
|
||
return 1;
|
||
|
||
code = GET_CODE (in);
|
||
|
||
switch (code)
|
||
{
|
||
/* Compare registers by number. */
|
||
case REG:
|
||
return GET_CODE (reg) == REG && REGNO (in) == REGNO (reg);
|
||
|
||
/* These codes have no constituent expressions
|
||
and are unique. */
|
||
case CC0:
|
||
case PC:
|
||
case CONST_INT:
|
||
case CONST_DOUBLE:
|
||
case SYMBOL_REF:
|
||
case CODE_LABEL:
|
||
return 0;
|
||
}
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
{
|
||
if (fmt[i] == 'E')
|
||
{
|
||
register int j;
|
||
for (j = XVECLEN (in, i) - 1; j >= 0; j--)
|
||
if (only_reg_use_p (reg, expr, XVECEXP (in, i, j)))
|
||
return 1;
|
||
}
|
||
else if (fmt[i] == 'e'
|
||
&& only_reg_use_p (reg, expr, XEXP (in, i)))
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Scan X for memory refs and check each memory address
|
||
as a possible giv. INSN is the insn whose pattern X comes from.
|
||
MAYBE_NEVER is 1 if the loop might execute INSN zero times. */
|
||
|
||
static void
|
||
find_mem_givs (x, insn, maybe_never, loop_end)
|
||
rtx x;
|
||
rtx insn;
|
||
int maybe_never;
|
||
rtx loop_end;
|
||
{
|
||
register int i, j;
|
||
register enum rtx_code code;
|
||
register char *fmt;
|
||
|
||
if (x == 0)
|
||
return;
|
||
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case REG:
|
||
case CONST_INT:
|
||
case CONST:
|
||
case CONST_DOUBLE:
|
||
case SYMBOL_REF:
|
||
case LABEL_REF:
|
||
case PC:
|
||
case CC0:
|
||
case ADDR_VEC:
|
||
case ADDR_DIFF_VEC:
|
||
case USE:
|
||
case CLOBBER:
|
||
return;
|
||
|
||
case MEM:
|
||
{
|
||
int src_regno;
|
||
rtx add_val;
|
||
rtx mult_val;
|
||
int benefit;
|
||
struct induction *forces = 0;
|
||
struct induction *forces2 = 0;
|
||
|
||
benefit = general_induction_var (XEXP (x, 0),
|
||
&src_regno, &add_val, &mult_val,
|
||
&forces, &forces2);
|
||
if (benefit > 0)
|
||
{
|
||
/* Found one; record it. */
|
||
struct induction *v =
|
||
(struct induction *) oballoc (sizeof (struct induction));
|
||
|
||
record_giv (v, insn, src_regno, 0, mult_val, add_val, benefit,
|
||
forces, forces2, DEST_ADDR, maybe_never, &XEXP (x, 0),
|
||
loop_end);
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* Recursively scan the subexpressions for other mem refs. */
|
||
|
||
fmt = GET_RTX_FORMAT (code);
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
if (fmt[i] == 'e')
|
||
find_mem_givs (XEXP (x, i), insn, maybe_never, loop_end);
|
||
else if (fmt[i] == 'E')
|
||
for (j = 0; j < XVECLEN (x, i); j++)
|
||
find_mem_givs (XVECEXP (x, i, j), insn, maybe_never, loop_end);
|
||
}
|
||
|
||
/* Fill in the data about one giv.
|
||
V is the `struct induction' in which we record the giv. (It is
|
||
allocated by the caller, with alloca.)
|
||
INSN is the insn that sets it.
|
||
BENEFIT estimates the savings from deleting this insn.
|
||
TYPE is DEST_REG or DEST_ADDR; it says whether the giv is computed
|
||
into a register or is used as a memory address.
|
||
|
||
SRC_REGNO is the biv reg number which the giv is computed from.
|
||
DEST_REGNO is the giv's reg number (if the giv is stored in a reg).
|
||
MULT_VAL and ADD_VAL are the coefficients used to compute the giv.
|
||
FORCES and FORCES2, if nonzero, are other `struct induction's for
|
||
other givs which are used to compute this giv indirectly.
|
||
LOCATION points to the place where this giv's value appears in INSN. */
|
||
|
||
static void
|
||
record_giv (v, insn, src_regno, dest_regno, mult_val, add_val, benefit,
|
||
forces, forces2, type, maybe_never, location, loop_end)
|
||
struct induction *v;
|
||
rtx insn;
|
||
int src_regno, dest_regno;
|
||
rtx mult_val, add_val;
|
||
int benefit;
|
||
struct induction *forces, *forces2;
|
||
enum g_types type;
|
||
int maybe_never;
|
||
rtx *location;
|
||
rtx loop_end;
|
||
{
|
||
struct induction *b;
|
||
struct iv_class *bl;
|
||
|
||
v->insn = insn;
|
||
v->src_regno = src_regno;
|
||
v->giv_type = type;
|
||
v->dest_regno = dest_regno;
|
||
v->mult_val = mult_val;
|
||
v->add_val = add_val;
|
||
v->benefit = benefit;
|
||
v->location = location;
|
||
|
||
if (type == DEST_ADDR)
|
||
{
|
||
v->mode = GET_MODE (*location);
|
||
v->consec = 0;
|
||
v->lifetime = 1;
|
||
v->times_used = 1;
|
||
}
|
||
else /* type == DEST_REG */
|
||
{
|
||
v->mode = GET_MODE (SET_DEST (PATTERN (insn)));
|
||
v->consec = n_times_set[dest_regno] - 1;
|
||
v->lifetime = (uid_luid[regno_last_uid[dest_regno]]
|
||
- uid_luid[regno_first_uid[dest_regno]]);
|
||
v->times_used = n_times_used[dest_regno];
|
||
}
|
||
|
||
v->same = 0;
|
||
v->forces = 0;
|
||
v->forces2 = 0;
|
||
v->ignore = 0;
|
||
v->new_reg = 0;
|
||
|
||
/* Mark giv as forced if it is only used to compute another giv. */
|
||
|
||
/* This check is not sufficient as INSN may have been moved giving
|
||
it a new uid, so make another check by calculating lifetimes.
|
||
This is overconservative but seems to be correct. */
|
||
|
||
if (forces)
|
||
{
|
||
v->benefit += forces->benefit;
|
||
if ((regno_last_uid[forces->dest_regno] == INSN_UID (insn)
|
||
||
|
||
((uid_luid[regno_last_uid[forces->dest_regno]]
|
||
- uid_luid[regno_first_uid[forces->dest_regno]])
|
||
== (INSN_LUID (insn) - INSN_LUID (forces->insn))))
|
||
&& !reg_used_between_p (SET_DEST (PATTERN (forces->insn)),
|
||
forces->insn, insn))
|
||
{
|
||
v->forces = forces;
|
||
forces->ignore = 1;
|
||
}
|
||
}
|
||
|
||
if (forces2)
|
||
{
|
||
v->benefit += forces2->benefit;
|
||
if ((regno_last_uid[forces2->dest_regno] == INSN_UID (insn)
|
||
||
|
||
((uid_luid[regno_last_uid[forces2->dest_regno]]
|
||
- uid_luid[regno_first_uid[forces2->dest_regno]])
|
||
== (INSN_LUID (insn) - INSN_LUID (forces2->insn))))
|
||
&& !reg_used_between_p (SET_DEST (PATTERN (forces2->insn)),
|
||
forces2->insn, insn))
|
||
{
|
||
if (v->forces)
|
||
v->forces2 = forces2;
|
||
else
|
||
v->forces = forces2;
|
||
forces2->ignore = 1;
|
||
}
|
||
}
|
||
|
||
if (type == DEST_REG)
|
||
{
|
||
induct_var[dest_regno] = GENERAL_INDUCT;
|
||
induct_struct[dest_regno] = v;
|
||
}
|
||
|
||
/* Add the giv to the class of givs computed from one biv. */
|
||
|
||
bl = class_struct[src_regno];
|
||
if (bl)
|
||
{
|
||
v->family = bl->giv;
|
||
bl->giv = v;
|
||
/* Don't count DEST_ADDR. This is supposed to count the number of
|
||
insns that calculate givs. */
|
||
if (type == DEST_REG)
|
||
bl->giv_count++;
|
||
bl->total_benefit += benefit;
|
||
}
|
||
else
|
||
/* Fatal error, biv missing for this giv? */
|
||
abort ();
|
||
|
||
if (type == DEST_ADDR)
|
||
v->replaceable = 1;
|
||
else
|
||
{
|
||
/* The giv can be replaced outright by the reduced register if
|
||
- the insn that sets the giv is always executed on any iteration
|
||
on which the giv is used at all
|
||
(there are two ways to deduce this:
|
||
either the insn is executed on every iteration,
|
||
or all uses follow that insn in the same basic block),
|
||
- the giv is not used before the insn that sets it,
|
||
i.e. no definition outside loop reaches into loop
|
||
- no assignments to the biv occur during the giv's lifetime. */
|
||
|
||
/* Is this right? Don't we need to make sure the giv is not used
|
||
outside the loop. Someday we will know where all the loop exits
|
||
are so we can do better, but until then....
|
||
March 18, 1989 -- self@bayes.arc.nasa.gov */
|
||
|
||
if (regno_first_uid[dest_regno] == INSN_UID (insn)
|
||
/* Previous line always fails if INSN was moved by loop opt. */
|
||
&& uid_luid[regno_last_uid[dest_regno]] < INSN_LUID (loop_end)
|
||
&& (!maybe_never || last_use_this_basic_block (dest_regno, insn)))
|
||
{
|
||
v->replaceable = 1;
|
||
for (b = bl->biv; b; b = b->family)
|
||
{
|
||
if ((uid_luid[INSN_UID (b->insn)] >= uid_luid[regno_first_uid[dest_regno]])
|
||
&&
|
||
(uid_luid[INSN_UID (b->insn)]
|
||
<= uid_luid[regno_last_uid[dest_regno]]))
|
||
{
|
||
v->replaceable = 0;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
v->replaceable = 0;
|
||
}
|
||
|
||
if (loop_dump_stream)
|
||
{
|
||
if (type == DEST_REG)
|
||
fprintf (loop_dump_stream, "Insn %d: giv reg %d",
|
||
INSN_UID (insn), dest_regno);
|
||
else
|
||
fprintf (loop_dump_stream, "Insn %d: dest address",
|
||
INSN_UID (insn));
|
||
|
||
fprintf (loop_dump_stream, " src reg %d benefit %d",
|
||
src_regno, v->benefit);
|
||
fprintf (loop_dump_stream, " used %d lifetime %d",
|
||
v->times_used, v->lifetime);
|
||
|
||
if (v->replaceable)
|
||
fprintf (loop_dump_stream, " replaceable");
|
||
|
||
if (GET_CODE (mult_val) == CONST_INT)
|
||
fprintf (loop_dump_stream, " mult %d",
|
||
INTVAL (mult_val));
|
||
else
|
||
{
|
||
fprintf (loop_dump_stream, " mult ");
|
||
print_rtl (loop_dump_stream, mult_val);
|
||
}
|
||
|
||
if (GET_CODE (add_val) == CONST_INT)
|
||
fprintf (loop_dump_stream, " add %d",
|
||
INTVAL (add_val));
|
||
else
|
||
{
|
||
fprintf (loop_dump_stream, " add ");
|
||
print_rtl (loop_dump_stream, add_val);
|
||
}
|
||
}
|
||
|
||
if (loop_dump_stream && v->forces)
|
||
fprintf (loop_dump_stream, " forces insn %d", INSN_UID (v->forces->insn));
|
||
if (loop_dump_stream && v->forces2)
|
||
fprintf (loop_dump_stream, " forces insn %d", INSN_UID (v->forces2->insn));
|
||
if (loop_dump_stream && v->consec)
|
||
fprintf (loop_dump_stream, " consec %d", v->consec);
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "\n");
|
||
}
|
||
|
||
/* Delete the insns forced by the insn described by V.
|
||
If THIS_TOO is nonzero, delete that insn itself as well. */
|
||
|
||
static void
|
||
delete_insn_forces (v, this_too)
|
||
struct induction *v;
|
||
int this_too;
|
||
{
|
||
rtx x, p;
|
||
int count;
|
||
rtx insn;
|
||
|
||
if (this_too)
|
||
{
|
||
insn = v->insn;
|
||
for (count = v->consec; count >= 0; count--)
|
||
{
|
||
/* If first insn of libcall sequence, skip to end. */
|
||
/* Do this at start of loop, since p is guaranteed to
|
||
be an insn here. */
|
||
if (x = find_reg_note (insn, REG_LIBCALL, 0))
|
||
insn = XEXP (x, 0);
|
||
|
||
if (x = find_reg_note (insn, REG_RETVAL, 0))
|
||
{
|
||
/* This is a library call; delete all insns backward until get to
|
||
first insn in this group. */
|
||
rtx first = XEXP (x, 0);
|
||
for (p = insn; p != first; p = PREV_INSN (p))
|
||
delete_insn (p);
|
||
/* Delete first insn also. */
|
||
delete_insn (p);
|
||
}
|
||
else
|
||
delete_insn (insn);
|
||
|
||
do insn = NEXT_INSN (insn);
|
||
while (GET_CODE (insn) == NOTE);
|
||
}
|
||
}
|
||
|
||
if (v->forces)
|
||
delete_insn_forces (v->forces, 1);
|
||
if (v->forces2)
|
||
delete_insn_forces (v->forces2, 1);
|
||
}
|
||
|
||
/* Check whether an insn is an increment legitimate for a basic induction var.
|
||
X is the source of the insn.
|
||
DEST_REG is the putative biv, also the destination of the insn.
|
||
We accept patterns of these forms:
|
||
REG = REG + INVARIANT
|
||
REG = INVARIANT + REG
|
||
REG = REG - CONSTANT
|
||
|
||
If X is suitable, we return 1,
|
||
and store the factor multiplying REF in X into *MULT_VAL
|
||
and the additive term into *INC_VAL.
|
||
Otherwise we return 0. */
|
||
|
||
static int
|
||
basic_induction_var (x, dest_regno, inc_val, mult_val)
|
||
register rtx x;
|
||
int dest_regno;
|
||
rtx *inc_val;
|
||
rtx *mult_val;
|
||
{
|
||
register enum rtx_code code;
|
||
rtx arg;
|
||
|
||
if (x == 0)
|
||
return 0;
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case PLUS:
|
||
if (GET_CODE (XEXP (x, 0)) == REG
|
||
&& REGNO (XEXP (x, 0)) == dest_regno)
|
||
arg = XEXP (x, 1);
|
||
else if (GET_CODE (XEXP (x, 1)) == REG
|
||
&& REGNO (XEXP (x, 1)) == dest_regno)
|
||
arg = XEXP (x, 0);
|
||
else
|
||
return 0;
|
||
|
||
if (invariant_p (arg) == 1)
|
||
*inc_val = arg;
|
||
else
|
||
return 0;
|
||
|
||
*mult_val = const1_rtx;
|
||
return 1;
|
||
|
||
case MINUS:
|
||
if (GET_CODE (XEXP (x, 0)) == REG
|
||
&& REGNO (XEXP (x, 0)) == dest_regno
|
||
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
|
||
*inc_val = gen_rtx (CONST_INT, VOIDmode,
|
||
- INTVAL (XEXP (x, 1)));
|
||
else
|
||
return 0;
|
||
*mult_val = const1_rtx;
|
||
return 1;
|
||
|
||
/* Can accept constant setting of biv only when inside inner most loop.
|
||
Otherwise, a biv of an inner loop may be incorrectly recognized
|
||
as a biv of the outer loop,
|
||
causing code to be moved INTO the inner loop. */
|
||
case REG:
|
||
if (!invariant_p (x))
|
||
return 0;
|
||
case CONST_INT:
|
||
case SYMBOL_REF:
|
||
case CONST:
|
||
if (loops_enclosed == 1)
|
||
{
|
||
*inc_val = x;
|
||
*mult_val = const0_rtx;
|
||
return 1;
|
||
}
|
||
else
|
||
return 0;
|
||
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/* A general induction variable (giv) is any quantity that is a linear function
|
||
of a basic induction variable, i.e. giv = biv * mult_val + add_val.
|
||
The coefficients can be any loop invariant quantity.
|
||
A giv need not be computed directly from the biv;
|
||
it can be computed by way of other givs. */
|
||
|
||
/* Determine whether X computes a giv.
|
||
If it does, return a nonzero value
|
||
which is the benefit from eliminating the computation of X;
|
||
set *SRC_REGNO to the register number of the biv that it is computed from;
|
||
set *ADD_VAL and *MULT_VAL to the coefficients,
|
||
such that the value of X is biv * mult + add;
|
||
set forces (and forces2) to identify any other givs that are used
|
||
solely to compute this one. */
|
||
|
||
/* This routine recognizes four types of patterns that generate givs:
|
||
- giv = biv op invariant v = 0, g = 0
|
||
- giv1 = giv2 op invariant v = 0, g = giv2
|
||
where giv1 and giv2 are functions of the same biv
|
||
- giv1 = biv op giv2 v = giv2, g = 0
|
||
where giv2 is a function of biv
|
||
- giv1 = giv2 op giv3 v = giv3, g = giv2
|
||
where giv2 and giv3 are functions of the save biv */
|
||
|
||
static int
|
||
general_induction_var (x, src_regno, add_val, mult_val, forces, forces2)
|
||
rtx x;
|
||
int *src_regno;
|
||
rtx *add_val;
|
||
rtx *mult_val;
|
||
struct induction **forces;
|
||
struct induction **forces2;
|
||
{
|
||
register enum rtx_code code;
|
||
rtx arg;
|
||
struct induction *g = 0;
|
||
struct induction *v = 0;
|
||
int subexp = 0;
|
||
int tem;
|
||
|
||
if (x == 0)
|
||
return 0;
|
||
|
||
code = GET_CODE (x);
|
||
switch (code)
|
||
{
|
||
case NEG:
|
||
/* This can generate givs also, but it is not handled. */
|
||
return 0;
|
||
|
||
case PLUS:
|
||
case MINUS:
|
||
case MULT:
|
||
case UMULT:
|
||
/* Result is linear in both operands. */
|
||
/* Determine which operand is the biv, and put the other in ARG. */
|
||
if (GET_CODE (XEXP (x, 0)) == REG
|
||
&& induct_var[REGNO (XEXP (x, 0))] == BASIC_INDUCT)
|
||
{
|
||
*src_regno = REGNO (XEXP (x, 0));
|
||
arg = XEXP (x, 1);
|
||
|
||
}
|
||
else if (GET_CODE (XEXP (x, 1)) == REG
|
||
&& induct_var[REGNO (XEXP (x, 1))] == BASIC_INDUCT)
|
||
{
|
||
*src_regno = REGNO (XEXP (x, 1));
|
||
arg = XEXP (x, 0);
|
||
|
||
}
|
||
/* Check for an rtl subexpression that is a giv. Memory address
|
||
givs often look like (plus (reg) (mult (biv) (const))). */
|
||
/* Do this before checking for a giv operand, as this function will
|
||
fail if this special operand is not recognized. */
|
||
#ifndef DONT_REDUCE_ADDR
|
||
else if (tem = general_induction_var (XEXP (x, 1), src_regno,
|
||
add_val, mult_val,
|
||
forces, forces2)
|
||
&& code != MINUS)
|
||
{
|
||
/* Set subexp true so that this can be handled a little
|
||
differently from the normal case of g set. */
|
||
/* Note that SRC_REGNO is already set. */
|
||
subexp = TRUE;
|
||
g = (struct induction *) alloca (sizeof (struct induction));
|
||
g->mult_val = *mult_val;
|
||
g->add_val = *add_val;
|
||
/* Fake out the test below. */
|
||
g->replaceable = 1;
|
||
/* Count this multiply as a shift, since that's what it
|
||
really will do. */
|
||
if (tem == MULT_BENEFIT)
|
||
g->benefit = SHIFT_BENEFIT;
|
||
else
|
||
g->benefit = tem;
|
||
arg = XEXP (x, 0);
|
||
}
|
||
#endif
|
||
/* Also allow general induction variables.
|
||
Could have a mult followed by an add (i.e. an address calculation),
|
||
thereby generating two related general induction variables
|
||
of which only the second is actually used. */
|
||
/* Do this after checking both args for basic induction variables. */
|
||
else if (GET_CODE (XEXP (x, 0)) == REG
|
||
&& induct_var[REGNO (XEXP (x, 0))] == GENERAL_INDUCT)
|
||
{
|
||
g = induct_struct[REGNO (XEXP (x, 0))];
|
||
*src_regno = g->src_regno;
|
||
arg = XEXP (x, 1);
|
||
}
|
||
else if (GET_CODE (XEXP (x, 1)) == REG
|
||
&& induct_var[REGNO (XEXP (x, 1))] == GENERAL_INDUCT
|
||
&& code != MINUS)
|
||
{
|
||
g = induct_struct[REGNO (XEXP (x, 1))];
|
||
*src_regno = g->src_regno;
|
||
arg = XEXP (x, 0);
|
||
}
|
||
else
|
||
return 0;
|
||
|
||
/* Overall form of expression looks good. */
|
||
break;
|
||
|
||
/* Could handle these also. */
|
||
case DIV:
|
||
case UDIV:
|
||
/* For a 68020 could handle these? */
|
||
case LSHIFT:
|
||
case ASHIFT:
|
||
case ASHIFTRT:
|
||
case LSHIFTRT:
|
||
/* These operations are linear only in first operand.
|
||
Check for a biv or giv there; if found, put other operand in ARG. */
|
||
if (GET_CODE (XEXP (x, 0)) == REG
|
||
&& induct_var[REGNO (XEXP (x, 0))] == BASIC_INDUCT)
|
||
{
|
||
*src_regno = REGNO (XEXP (x, 0));
|
||
arg = XEXP (x, 1);
|
||
}
|
||
/* Also allow general induction variable. */
|
||
else if (GET_CODE (XEXP (x, 0)) == REG
|
||
&& induct_var[REGNO (XEXP (x, 0))] == GENERAL_INDUCT)
|
||
{
|
||
g = induct_struct[REGNO (XEXP (x, 0))];
|
||
*src_regno = g->src_regno;
|
||
arg = XEXP (x, 1);
|
||
}
|
||
else
|
||
return 0;
|
||
|
||
/* Overall form of expression looks good. */
|
||
break;
|
||
|
||
default:
|
||
return 0;
|
||
}
|
||
|
||
/* ARG is the operand that is NOT a biv or giv.
|
||
Test it for superficial validity. */
|
||
|
||
/* This is just a special case of invariant values,
|
||
it is not really needed, but it's a shortcut. */
|
||
if (GET_CODE (arg) == CONST_INT)
|
||
;
|
||
|
||
/* Depends on previous general induction variable, which has
|
||
the same basic induction variable */
|
||
/* This code detects mults that have been generated as shift and add. */
|
||
else if (GET_CODE (arg) == REG
|
||
&& induct_var[REGNO (arg)] == GENERAL_INDUCT
|
||
&& induct_struct[REGNO (arg)]->src_regno == *src_regno)
|
||
{
|
||
v = induct_struct[REGNO (arg)];
|
||
/* Dependence indicated by forces, sort of kludgey. */
|
||
}
|
||
|
||
/* Invariant expression, could be a constant-valued register. */
|
||
else if (invariant_p (arg) == 1)
|
||
;
|
||
|
||
/* Failure */
|
||
else
|
||
return 0;
|
||
|
||
/* Until we can do the correct thing, suppress use of nonreplaceable givs
|
||
as sources for other givs. */
|
||
if ((g && ! g->replaceable)
|
||
|| (v && ! v->replaceable))
|
||
return 0;
|
||
|
||
/* Now we know looks like a giv; extract the coefficients.
|
||
We can still fail if the coefficients are not what we can handle. */
|
||
|
||
/* Only succeed if result mult_val and add_val are only one level of rtl,
|
||
for example, (NEG:SI (REG:SI 34)) is not accepted.
|
||
This mainly causes problems with the MINUS code. */
|
||
|
||
switch (code)
|
||
{
|
||
case PLUS:
|
||
if (v && g)
|
||
{
|
||
if (GET_CODE (g->mult_val) == CONST_INT)
|
||
{
|
||
if (g->mult_val == const0_rtx)
|
||
*mult_val = v->mult_val;
|
||
else if (GET_CODE (v->mult_val) == CONST_INT)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->mult_val)
|
||
+ INTVAL (v->mult_val));
|
||
else
|
||
return 0;
|
||
}
|
||
else if (v->mult_val == const0_rtx)
|
||
*mult_val = g->mult_val;
|
||
else
|
||
return 0;
|
||
|
||
if (GET_CODE (g->add_val) == CONST_INT)
|
||
{
|
||
if (g->add_val == const0_rtx)
|
||
*add_val = v->add_val;
|
||
else if (GET_CODE (v->add_val) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->add_val)
|
||
+ INTVAL (v->add_val));
|
||
else
|
||
return 0;
|
||
}
|
||
else if (v->add_val == const0_rtx)
|
||
*add_val = g->add_val;
|
||
else
|
||
return 0;
|
||
|
||
if (subexp)
|
||
{
|
||
/* g deleted when return, can't return pointer to it */
|
||
if (*forces2 == 0)
|
||
*forces2 = v;
|
||
return ADD_BENEFIT + g->benefit;
|
||
}
|
||
else
|
||
{
|
||
*forces = g;
|
||
*forces2 = v;
|
||
return ADD_BENEFIT;
|
||
}
|
||
}
|
||
else if (v)
|
||
{
|
||
if (GET_CODE (v->mult_val) == CONST_INT)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (v->mult_val) + 1);
|
||
else
|
||
return 0;
|
||
*add_val = v->add_val;
|
||
*forces = v;
|
||
return ADD_BENEFIT;
|
||
}
|
||
else if (g)
|
||
{
|
||
*mult_val = g->mult_val;
|
||
if (GET_CODE (g->add_val) == CONST_INT)
|
||
{
|
||
if (g->add_val == const0_rtx)
|
||
*add_val = arg;
|
||
else if (GET_CODE (arg) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->add_val) + INTVAL (arg));
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
/* Could succeed if arg == 0, but that will never occur. */
|
||
return 0;
|
||
|
||
if (subexp)
|
||
/* g deleted when return, can't return pointer to it */
|
||
return ADD_BENEFIT + g->benefit;
|
||
else
|
||
{
|
||
*forces = g;
|
||
return ADD_BENEFIT;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*mult_val = const1_rtx;
|
||
*add_val = arg;
|
||
return ADD_BENEFIT;
|
||
}
|
||
|
||
/* Takes a lot of code and will rarely succeed. */
|
||
case MINUS:
|
||
if (v && g)
|
||
{
|
||
/* G is the first argument of MINUS. */
|
||
|
||
if (GET_CODE (g->mult_val) == CONST_INT)
|
||
{
|
||
if (g->mult_val == const0_rtx)
|
||
#if 0 /* Should not have to fail here */
|
||
*mult_val = gen_rtx (NEG, SImode, v->mult_val);
|
||
#endif
|
||
return 0;
|
||
else if (GET_CODE (v->mult_val) == CONST_INT)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->mult_val)
|
||
- INTVAL (v->mult_val));
|
||
else
|
||
return 0;
|
||
}
|
||
else if (v->mult_val == const0_rtx)
|
||
*mult_val = g->mult_val;
|
||
else
|
||
return 0;
|
||
|
||
if (GET_CODE (g->add_val) == CONST_INT)
|
||
{
|
||
if (g->add_val == const0_rtx)
|
||
#if 0 /* should not have to fail here */
|
||
*add_val = v->add_val;
|
||
#endif
|
||
return 0;
|
||
else if (GET_CODE (v->add_val) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->add_val)
|
||
- INTVAL (v->add_val));
|
||
else
|
||
return 0;
|
||
}
|
||
else if (v->add_val == const0_rtx)
|
||
*add_val = g->add_val;
|
||
else
|
||
return 0;
|
||
|
||
if (subexp)
|
||
{
|
||
/* G deleted when return, can't return pointer to it */
|
||
if (*forces2 == 0)
|
||
*forces2 = v;
|
||
return ADD_BENEFIT + g->benefit;
|
||
}
|
||
else
|
||
{
|
||
*forces = g;
|
||
*forces2 = v;
|
||
return ADD_BENEFIT;
|
||
}
|
||
}
|
||
else if (v)
|
||
{
|
||
if (GET_CODE (v->mult_val) != CONST_INT)
|
||
return 0;
|
||
if (arg == XEXP (x, 0)) /* giv1 = giv2 - biv */
|
||
{
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (v->mult_val) - 1);
|
||
*add_val = v->add_val;
|
||
}
|
||
else /* giv1 = biv - giv2 */
|
||
{
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
1 - INTVAL (v->mult_val));
|
||
if (GET_CODE (v->add_val) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
- INTVAL (v->add_val));
|
||
else
|
||
return 0;
|
||
}
|
||
*forces = v;
|
||
return ADD_BENEFIT;
|
||
}
|
||
else if (g)
|
||
{
|
||
if (arg == XEXP (x, 1))
|
||
*mult_val = g->mult_val;
|
||
else
|
||
{
|
||
if (GET_CODE (g->mult_val) == CONST_INT)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
- INTVAL (g->mult_val));
|
||
else
|
||
return 0;
|
||
}
|
||
if (GET_CODE (g->add_val) == CONST_INT)
|
||
{
|
||
if (g->add_val == const0_rtx)
|
||
{
|
||
if (arg == XEXP (x, 1)) /* giv1 = giv2 - arg */
|
||
{
|
||
/* Fail unless arg is a constant. */
|
||
if (GET_CODE (arg) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
-INTVAL (arg));
|
||
else
|
||
return 0;
|
||
}
|
||
else /* giv1 = arg - giv2 */
|
||
*add_val = arg;
|
||
}
|
||
else if (GET_CODE (arg) == CONST_INT)
|
||
{
|
||
if (arg == XEXP (x, 1)) /* giv1 = giv2 - arg */
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->add_val)
|
||
- INTVAL (arg));
|
||
else /* giv1 = arg - giv2 */
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (arg),
|
||
- INTVAL (g->add_val));
|
||
}
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
/* Could succeed if arg == 0, but that will never occur. */
|
||
return 0;
|
||
|
||
if (subexp)
|
||
/* G deleted when return, can't return pointer to it. */
|
||
return ADD_BENEFIT + g->benefit;
|
||
else
|
||
{
|
||
*forces = g;
|
||
return ADD_BENEFIT;
|
||
}
|
||
}
|
||
else if (GET_CODE (arg) == CONST_INT)
|
||
{
|
||
if (arg == XEXP (x, 1))
|
||
{
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode, - INTVAL (arg));
|
||
*mult_val = const1_rtx;
|
||
}
|
||
else
|
||
{
|
||
*add_val = arg;
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode, -1);
|
||
}
|
||
return ADD_BENEFIT;
|
||
}
|
||
else
|
||
return 0;
|
||
|
||
/* UMULT can be handled like MULT since C ignores overflows. */
|
||
case MULT:
|
||
case UMULT:
|
||
if (v && g)
|
||
{
|
||
/* Quadratic term, just fail. */
|
||
return 0;
|
||
}
|
||
else if (v)
|
||
{
|
||
/* Quadratic term, just fail. */
|
||
return 0;
|
||
}
|
||
else if (g)
|
||
{
|
||
/* Takes a lot of code and will rarely succeed. */
|
||
/* dest = m * arg * b + a * arg */
|
||
if (GET_CODE (g->mult_val) == CONST_INT)
|
||
{
|
||
if (g->mult_val == const0_rtx)
|
||
*mult_val = const0_rtx;
|
||
else if (g->mult_val == const1_rtx)
|
||
*mult_val = arg;
|
||
else if (GET_CODE (arg) == CONST_INT)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->mult_val) * INTVAL (arg));
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
/* Could suceed if arg == 1 or 0, but this will never occur. */
|
||
return 0;
|
||
|
||
if (GET_CODE (g->add_val) == CONST_INT)
|
||
{
|
||
if (g->add_val == const0_rtx)
|
||
*add_val = const0_rtx;
|
||
else if (g->add_val == const1_rtx)
|
||
*add_val = arg;
|
||
else if (GET_CODE (arg) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->add_val) * INTVAL (arg));
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
/* Could suceed if arg == 1 or 0, but this will never occur. */
|
||
return 0;
|
||
|
||
if (subexp)
|
||
/* G deleted when return, can't return pointer to it. */
|
||
return MULT_BENEFIT + g->benefit;
|
||
else
|
||
{
|
||
*forces = g;
|
||
return MULT_BENEFIT;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*mult_val = arg;
|
||
*add_val = const0_rtx;
|
||
return MULT_BENEFIT;
|
||
}
|
||
|
||
/* These are not worth the trouble. */
|
||
case DIV:
|
||
case UDIV:
|
||
return 0;
|
||
|
||
/* Handle these, but only for left shift. */
|
||
case LSHIFT:
|
||
case ASHIFT:
|
||
if (v && g)
|
||
{
|
||
/* Quadratic term, just fail. */
|
||
return 0;
|
||
}
|
||
else if (v)
|
||
{
|
||
/* Quadratic term, just fail. */
|
||
return 0;
|
||
}
|
||
else if (g)
|
||
{
|
||
/* Takes a lot of code and will rarely succeed. */
|
||
/* dest = ((m * b) << arg) + (a << arg) */
|
||
if (GET_CODE (g->mult_val) == CONST_INT)
|
||
{
|
||
if (g->mult_val == const0_rtx)
|
||
*mult_val = const0_rtx;
|
||
else if (GET_CODE (arg) == CONST_INT && INTVAL (arg) >= 0)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->mult_val)
|
||
* (1 << INTVAL (arg)));
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
/* Could suceed if arg == 0, but this will never occur. */
|
||
return 0;
|
||
|
||
if (GET_CODE (g->add_val) == CONST_INT)
|
||
{
|
||
if (g->add_val == const0_rtx)
|
||
*add_val = const0_rtx;
|
||
else if (GET_CODE (arg) == CONST_INT)
|
||
*add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
INTVAL (g->add_val)
|
||
* (1 << INTVAL (arg)));
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
/* Could suceed if arg == 0, but this will never occur. */
|
||
return 0;
|
||
|
||
if (subexp)
|
||
/* G deleted when return, can't return pointer to it. */
|
||
return SHIFT_BENEFIT + g->benefit;
|
||
else
|
||
{
|
||
*forces = g;
|
||
return SHIFT_BENEFIT;
|
||
}
|
||
}
|
||
|
||
if (GET_CODE (arg) == CONST_INT && INTVAL (arg) >= 0)
|
||
*mult_val = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (arg));
|
||
else
|
||
return 0;
|
||
*add_val = const0_rtx;
|
||
return SHIFT_BENEFIT;
|
||
|
||
/* These are not worth the trouble. */
|
||
case ASHIFTRT:
|
||
case LSHIFTRT:
|
||
return 0;
|
||
|
||
/* should never reach here */
|
||
default:
|
||
abort ();
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/* Help detect a giv that is calculated by several consecutive insns;
|
||
for example,
|
||
giv = biv * M
|
||
giv = giv + A
|
||
The caller has already identified the first insn P as having a giv as dest;
|
||
we check that all other insns that set the same register follow
|
||
immediately after P, that they alter nothing else,
|
||
and that the result of the last is still a giv.
|
||
|
||
The value is 0 if the reg set in P is not really a giv.
|
||
Otherwise, the value is the amount gained by eliminating
|
||
all the consecutive insns that compute the value.
|
||
|
||
FIRST_BENEFIT is the amount gained by eliminating the first insn, P.
|
||
SRC_REGNO is the regno of the biv; DEST_REGNO is that of the giv.
|
||
|
||
The coefficients of the ultimate giv value are stored in
|
||
*MULT_VAL and *ADD_VAL. */
|
||
|
||
static int
|
||
consec_sets_giv (first_benefit, p, src_regno, dest_regno,
|
||
add_val, mult_val)
|
||
int first_benefit;
|
||
rtx p;
|
||
int src_regno;
|
||
int dest_regno;
|
||
rtx *add_val;
|
||
rtx *mult_val;
|
||
{
|
||
int count;
|
||
int benefit = first_benefit;
|
||
enum rtx_code code;
|
||
struct induction forces, forces2;
|
||
rtx temp;
|
||
int tem;
|
||
|
||
/* Initialize info used by general_induction_var. */
|
||
struct induction *v =
|
||
(struct induction *) oballoc (sizeof (struct induction));
|
||
v->src_regno = src_regno;
|
||
v->mult_val = *mult_val;
|
||
v->add_val = *add_val;
|
||
|
||
induct_var[dest_regno] = GENERAL_INDUCT;
|
||
induct_struct[dest_regno] = v;
|
||
|
||
count = n_times_set[dest_regno] - 1;
|
||
|
||
while (count > 0)
|
||
{
|
||
p = NEXT_INSN (p);
|
||
code = GET_CODE (p);
|
||
|
||
/* If libcall, skip to end of call sequence. */
|
||
if (code == INSN && (temp = find_reg_note (p, REG_LIBCALL, 0)))
|
||
p = XEXP (temp, 0);
|
||
|
||
if (code == INSN && GET_CODE (PATTERN (p)) == SET
|
||
&& GET_CODE (SET_DEST (PATTERN (p))) == REG
|
||
&& REGNO (SET_DEST (PATTERN (p))) == dest_regno
|
||
&& ((tem = general_induction_var (SET_SRC (PATTERN (p)), &src_regno,
|
||
add_val, mult_val,
|
||
&forces, &forces2))
|
||
/* Giv created by call to library routine. */
|
||
|| ((temp = find_reg_note (p, REG_EQUAL, 0)) &&
|
||
(tem = general_induction_var (XEXP (temp, 0), &src_regno,
|
||
add_val, mult_val,
|
||
&forces, &forces2))))
|
||
&& src_regno == v->src_regno)
|
||
{
|
||
count--;
|
||
benefit += tem;
|
||
v->mult_val = *mult_val;
|
||
v->add_val = *add_val;
|
||
}
|
||
else if (code != NOTE)
|
||
{
|
||
induct_var[dest_regno] = UNKNOWN_INDUCT;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return benefit;
|
||
}
|
||
|
||
/* Generate a SEQUENCE to multiply OP0 and OP1 with result in TARGET.
|
||
Use expand_mult to "optimally" do the multiply.
|
||
This also works for machines that do not have multiply insns.
|
||
If one of the operands is a constant, it must be the second. */
|
||
|
||
static rtx
|
||
gen_iv_mult (mode, op0, op1, target)
|
||
enum machine_mode mode;
|
||
register rtx op0, op1, target;
|
||
{
|
||
extern rtx gen_sequence ();
|
||
extern rtx start_sequence ();
|
||
rtx saved, result, temp;
|
||
|
||
saved = start_sequence ();
|
||
|
||
/* ??? It is very unmodular to use expand_mult here!
|
||
This should be redesigned. */
|
||
|
||
/* UNSIGNEDP arg can be zero since operands/target always same width. */
|
||
temp = expand_mult (mode, op0, op1, target, 0);
|
||
|
||
/* Move to target register, if expand_mult did not put it there. */
|
||
if (target != 0 && temp != target)
|
||
emit_move_insn (target, temp);
|
||
|
||
result = gen_sequence ();
|
||
end_sequence (saved);
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Emit code to initialize an induction variable created by strength
|
||
reduction.
|
||
More precisely, emit code before INSERT_BEFORE
|
||
to set REG = B * M + A. */
|
||
|
||
static void
|
||
emit_iv_init_code (b, m, a, reg, insert_before)
|
||
rtx b; /* initial value of basic induction variable */
|
||
rtx m; /* multiplicative constant */
|
||
rtx a; /* additive constant */
|
||
rtx reg; /* destination register */
|
||
rtx insert_before;
|
||
{
|
||
rtx seq;
|
||
rtx result;
|
||
|
||
/* Prevent unexpected sharing of these rtx. */
|
||
a = copy_rtx (a);
|
||
b = copy_rtx (b);
|
||
|
||
start_sequence ();
|
||
result = expand_mult_add (b, m, a, GET_MODE (reg), 0);
|
||
if (reg != result)
|
||
emit_move_insn (reg, result);
|
||
seq = gen_sequence ();
|
||
end_sequence ();
|
||
|
||
emit_insn_before (seq, insert_before);
|
||
}
|
||
|
||
/* Emit code to increment the induction variable inside the loop.
|
||
Try to emit optimal code for the expression
|
||
REG = REG + BIV_ADD * GIV_MULT. */
|
||
|
||
static void
|
||
emit_iv_inc (biv_add, giv_mult, reg, insn)
|
||
rtx biv_add; /* increment value for biv */
|
||
rtx giv_mult; /* multiply value of giv */
|
||
rtx reg; /* create insn to set this reg */
|
||
rtx insn; /* where to insert the new insn */
|
||
{
|
||
emit_iv_init_code (biv_add, giv_mult, reg, reg, insn);
|
||
}
|
||
|
||
/* Test whethen BIV_ADD * GIV_MULT can be computed without
|
||
an actual multiply insn. Value is 1 if so. */
|
||
|
||
static int
|
||
product_cheap_p (biv_add, giv_mult)
|
||
rtx biv_add;
|
||
rtx giv_mult;
|
||
{
|
||
/* Indicates which of MULT/ADD are constants. */
|
||
int status = 0;
|
||
int const_val;
|
||
rtx tmp;
|
||
|
||
if (GET_CODE (biv_add) == CONST_INT)
|
||
status |= 0x1;
|
||
if (GET_CODE (giv_mult) == CONST_INT)
|
||
status |= 0x2;
|
||
|
||
switch (status)
|
||
{
|
||
case 0:
|
||
/* Neither is constant: would need a multiply insn, so fail. */
|
||
return 0;
|
||
|
||
case 1:
|
||
/* BIV_ADD value is constant */
|
||
/* Equivalent to state 2, just switch values of BIV_ADD and GIV_MULT
|
||
and fall through. */
|
||
tmp = biv_add;
|
||
biv_add = giv_mult;
|
||
giv_mult = tmp;
|
||
|
||
case 2:
|
||
/* GIV_MULT value is constant.
|
||
If it is 1, 0 or -1 then we win. */
|
||
const_val = INTVAL (giv_mult);
|
||
if (const_val < -1 || const_val > 1)
|
||
{
|
||
tmp = gen_iv_mult (GET_MODE (biv_add), biv_add, giv_mult, 0);
|
||
/* Don't emit a multiply insn, just fail instead. */
|
||
if ((GET_CODE (tmp) == SET && GET_CODE (SET_SRC (tmp)) == MULT)
|
||
/* Also fail if library call (which generates more
|
||
then two insn) is needed. */
|
||
|| (GET_CODE (tmp) == SEQUENCE && XVECLEN (tmp, 0) > 2))
|
||
return 0;
|
||
}
|
||
return 1;
|
||
|
||
case 3:
|
||
/* Both BIV_ADD and GIV_MULT are constant;
|
||
can compute the product at compile time. */
|
||
return 1;
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
}
|
||
|
||
|
||
/* Check to see if loop can be terminated by a "decrement and branch until
|
||
zero" instruction. If so, add a REG_NONNEG note to the branch insn if so.
|
||
Also try reversing an increment loop to a decrement loop
|
||
to see if the optimization can be performed.
|
||
Value is nonzero if optimization was performed. */
|
||
|
||
static int
|
||
check_dbra_loop (loop_end, iv_list, insn_count, loop_start)
|
||
rtx loop_end;
|
||
struct iv_class *iv_list;
|
||
int insn_count;
|
||
rtx loop_start;
|
||
{
|
||
struct iv_class *bl;
|
||
rtx reg;
|
||
rtx jump_label;
|
||
rtx final_value;
|
||
rtx start_value;
|
||
enum rtx_code branch_code;
|
||
rtx new_add_val;
|
||
rtx tested_before_loop = 0;
|
||
rtx p;
|
||
|
||
/* See if the loop is contained in `if (X >= 0)' for some reg X.
|
||
If so, then we know X is initially nonnegative even though
|
||
we don't know its initial value.
|
||
Record X in TESTED_BEFORE_LOOP. */
|
||
|
||
for (p = loop_start; p != 0; p = PREV_INSN (p))
|
||
if (GET_CODE (p) != NOTE)
|
||
break;
|
||
|
||
/* See if a conditional branch preceeds the loop.
|
||
There may be no other insns or labels between it and
|
||
the beginning of the loop. */
|
||
if (p != 0 && GET_CODE (p) == JUMP_INSN && condjump_p (p)
|
||
&& SET_SRC (PATTERN (p)) != pc_rtx
|
||
&& ((GET_CODE (XEXP (SET_SRC (PATTERN (p)), 0)) == LT
|
||
&& XEXP (SET_SRC (PATTERN (p)), 2) == pc_rtx)
|
||
||
|
||
(GET_CODE (XEXP (SET_SRC (PATTERN (p)), 0)) == GE
|
||
&& XEXP (SET_SRC (PATTERN (p)), 1) == pc_rtx))
|
||
&& next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end))
|
||
{
|
||
/* Before the branch should be a test or compare.
|
||
See if we are comparing something against zero. */
|
||
p = PREV_INSN (p);
|
||
if (GET_CODE (p) == INSN && GET_CODE (PATTERN (p)) == SET
|
||
&& SET_DEST (PATTERN (p)) == cc0_rtx)
|
||
{
|
||
if (GET_CODE (SET_SRC (PATTERN (p))) == REG)
|
||
tested_before_loop = SET_SRC (PATTERN (p));
|
||
else if (GET_CODE (SET_SRC (PATTERN (p))) == COMPARE
|
||
&& GET_CODE (XEXP (SET_SRC (PATTERN (p)), 0)) == REG
|
||
&& XEXP (SET_SRC (PATTERN (p)), 1) == const0_rtx)
|
||
tested_before_loop = XEXP (SET_SRC (PATTERN (p)), 0);
|
||
else if (GET_CODE (SET_SRC (PATTERN (p))) == COMPARE
|
||
&& GET_CODE (XEXP (SET_SRC (PATTERN (p)), 1)) == REG
|
||
&& XEXP (SET_SRC (PATTERN (p)), 0) == const0_rtx)
|
||
tested_before_loop = XEXP (SET_SRC (PATTERN (p)), 1);
|
||
}
|
||
}
|
||
|
||
/* If last insn is a conditional branch, and the insn before tests a register
|
||
value, then try to optimize it. */
|
||
|
||
if (GET_CODE (PREV_INSN (loop_end)) == JUMP_INSN
|
||
&& GET_CODE (PATTERN (PREV_INSN (loop_end))) == SET
|
||
&& GET_CODE (SET_SRC (PATTERN (PREV_INSN (loop_end)))) == IF_THEN_ELSE
|
||
&& GET_CODE (PREV_INSN (PREV_INSN (loop_end))) == INSN
|
||
&& GET_CODE (PATTERN (PREV_INSN (PREV_INSN (loop_end)))) == SET
|
||
&& (GET_CODE (SET_DEST (PATTERN (PREV_INSN (PREV_INSN (loop_end))))) ==
|
||
CC0))
|
||
{
|
||
/* Check all of the bivs to see if the compare uses one of them. */
|
||
|
||
for (bl = iv_list; bl; bl = bl->next)
|
||
{
|
||
if (reg_mentioned_p (SET_DEST (PATTERN (bl->biv->insn)),
|
||
PREV_INSN (PREV_INSN (loop_end))))
|
||
break;
|
||
}
|
||
|
||
/* If biv set more than once, then give up.
|
||
We can't guarantee that it will be zero on the last iteration.
|
||
Also give up if the biv is used between its update and the test
|
||
insn. */
|
||
if (bl && bl->biv_count == 1
|
||
&& ! reg_used_between_p (regno_reg_rtx[bl->regno], bl->biv->insn,
|
||
PREV_INSN (PREV_INSN (loop_end))))
|
||
{
|
||
/* Look for the case where the basic induction variable is always
|
||
nonnegative, and equals zero on the last iteration.
|
||
In this case, add a reg_note REG_NONNEG, which allows the
|
||
m68k DBRA instruction to be used. */
|
||
|
||
/* the decrement case */
|
||
|
||
if (GET_CODE (bl->biv->add_val) == CONST_INT
|
||
&& INTVAL (bl->biv->add_val) < 0)
|
||
{
|
||
/* Initial value must be greater than 0,
|
||
init_val % -dec_value == 0 to ensure that it equals zero on
|
||
the last iteration */
|
||
|
||
if (GET_CODE (bl->initial_value) == CONST_INT
|
||
&& INTVAL (bl->initial_value) > 0
|
||
&& (INTVAL (bl->initial_value) %
|
||
(-INTVAL (bl->biv->add_val))) == 0)
|
||
{
|
||
/* register always nonnegative, add REG_NOTE to branch */
|
||
REG_NOTES (PREV_INSN (loop_end))
|
||
= gen_rtx (EXPR_LIST, REG_NONNEG, 0,
|
||
REG_NOTES (PREV_INSN (loop_end)));
|
||
bl->nonneg = 1;
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* If the decrement is 1 and the value was tested as >= 0 before
|
||
the loop, then we can safely optimize. */
|
||
if (SET_DEST (PATTERN (bl->biv->insn)) == tested_before_loop
|
||
&& INTVAL (bl->biv->add_val) == -1)
|
||
{
|
||
REG_NOTES (PREV_INSN (loop_end))
|
||
= gen_rtx (EXPR_LIST, REG_NONNEG, 0,
|
||
REG_NOTES (PREV_INSN (loop_end)));
|
||
bl->nonneg = 1;
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
else if (num_mem_sets <= 1)
|
||
{
|
||
/* Try to change inc to dec, so can apply above optimization. */
|
||
/* Can do this if:
|
||
all registers modified are induction variables or invariant,
|
||
all memory references have non-overlapping addresses
|
||
(obviously true if only one write)
|
||
allow 2 insns for the compare/jump at the end of the loop. */
|
||
int num_nonfixed_reads = 0;
|
||
rtx p;
|
||
|
||
for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
|
||
if (GET_CODE (p) == INSN || GET_CODE (p) == CALL_INSN
|
||
|| GET_CODE (p) == JUMP_INSN)
|
||
num_nonfixed_reads += count_nonfixed_reads (PATTERN (p));
|
||
|
||
/* This code only acts for innermost loops. Also it simplifies
|
||
the memory address check by only reversing loops with
|
||
zero or one memory access.
|
||
Two memory accesses could involve parts of the same array,
|
||
and that can't be reversed. */
|
||
|
||
if (num_nonfixed_reads <= 1
|
||
&& !loop_has_call
|
||
&& (bl->giv_count + bl->biv_count + num_mem_sets
|
||
+ num_movables + 2 == insn_count))
|
||
{
|
||
rtx src_two_before_end;
|
||
int constant;
|
||
int win;
|
||
|
||
/* Loop can be reversed. */
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Can reverse loop\n");
|
||
|
||
/* Now check other conditions:
|
||
initial_value must be zero,
|
||
final_value % add_val == 0, so that when reversed, the
|
||
biv will be zero on the last iteration. */
|
||
|
||
/* Calculating the final value non trivial.
|
||
If branch is (LT (CC0) (CONST 0),
|
||
then value in compare is final value.
|
||
If branch is (LE (CC0) (CONST 0),
|
||
then value in compare is final_value - add_val */
|
||
|
||
branch_code
|
||
= GET_CODE (XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 0));
|
||
src_two_before_end
|
||
= SET_SRC (PATTERN (PREV_INSN (PREV_INSN (loop_end))));
|
||
|
||
win = 1;
|
||
if (GET_CODE (src_two_before_end) == REG)
|
||
constant = 0;
|
||
else if (GET_CODE (src_two_before_end) == COMPARE
|
||
&& GET_CODE (XEXP (src_two_before_end, 1)) == CONST_INT)
|
||
constant = INTVAL (XEXP (src_two_before_end, 1));
|
||
else
|
||
win = 0;
|
||
|
||
if (win && bl->initial_value == const0_rtx
|
||
&& (branch_code == LT || branch_code == LE)
|
||
&& XEXP (XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 0), 1) == const0_rtx
|
||
&& (constant % INTVAL (bl->biv->add_val)) == 0)
|
||
{
|
||
/* Register will always be nonnegative, with value
|
||
0 on last iteration if loop reversed */
|
||
|
||
/* Save some info needed to produce the new insns. */
|
||
reg = SET_DEST (PATTERN (bl->biv->insn));
|
||
jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
|
||
new_add_val = gen_rtx (CONST_INT, VOIDmode,
|
||
- INTVAL (bl->biv->add_val));
|
||
|
||
|
||
if (branch_code == LT)
|
||
{
|
||
final_value
|
||
= gen_rtx (CONST_INT, VOIDmode, constant);
|
||
start_value
|
||
= gen_rtx (CONST_INT, VOIDmode,
|
||
(constant - INTVAL (bl->biv->add_val)));
|
||
}
|
||
else /* branch_code == LE */
|
||
{
|
||
start_value
|
||
= gen_rtx (CONST_INT, VOIDmode, constant);
|
||
final_value
|
||
= gen_rtx (CONST_INT, VOIDmode,
|
||
(constant + INTVAL (bl->biv->add_val)));
|
||
}
|
||
|
||
/* Initialize biv to start_value before loop start.
|
||
The old initializing insn will be deleted as a
|
||
dead store by flow.c. */
|
||
emit_insn_before (gen_rtx (SET, VOIDmode, reg,
|
||
start_value),
|
||
loop_start);
|
||
|
||
/* Add insn to decrement register, and delete insn
|
||
that incremented the register. */
|
||
emit_insn_before (gen_rtx (SET, VOIDmode, reg,
|
||
gen_rtx (PLUS, GET_MODE (reg), reg,
|
||
new_add_val)),
|
||
bl->biv->insn);
|
||
/* Update biv info to reflect its new status. */
|
||
bl->biv->insn = PREV_INSN (bl->biv->insn);
|
||
delete_insn (NEXT_INSN (bl->biv->insn));
|
||
|
||
/* Inc LABEL_NUSES so that delete_insn will
|
||
not delete the label. */
|
||
LABEL_NUSES (XEXP (jump_label, 0)) ++;
|
||
|
||
if (regno_last_uid[bl->regno] != INSN_UID (PREV_INSN (loop_end)))
|
||
emit_insn_after (gen_rtx (SET, VOIDmode, reg,
|
||
final_value),
|
||
loop_end);
|
||
|
||
/* Delete compare/branch at end of loop. */
|
||
delete_insn (PREV_INSN (loop_end));
|
||
delete_insn (PREV_INSN (loop_end));
|
||
|
||
/* Add new compare/branch insn at end of loop. */
|
||
emit_insn_before (gen_rtx (SET, VOIDmode, cc0_rtx, reg),
|
||
loop_end);
|
||
emit_jump_insn_before (gen_rtx (SET, VOIDmode, pc_rtx,
|
||
gen_rtx (IF_THEN_ELSE, VOIDmode,
|
||
gen_rtx (GE, VOIDmode, cc0_rtx,
|
||
const0_rtx),
|
||
jump_label,
|
||
pc_rtx)),
|
||
loop_end);
|
||
|
||
JUMP_LABEL (PREV_INSN (loop_end)) = XEXP (jump_label, 0);
|
||
/* Increment of LABEL_NUSES done above. */
|
||
|
||
/* Register is now always nonnegative,
|
||
so add REG_NONNEG note to the branch. */
|
||
REG_NOTES (PREV_INSN (loop_end))
|
||
= gen_rtx (EXPR_LIST, REG_NONNEG, 0,
|
||
REG_NOTES (PREV_INSN (loop_end)));
|
||
bl->nonneg = 1;
|
||
|
||
/* Update rest of biv info. */
|
||
bl->initial_value = start_value;
|
||
bl->biv->add_val = new_add_val;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Reversed loop and added reg_nonneg\n");
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Verify whether the biv BL appears to be eliminable,
|
||
based on the insns in the loop that refer to it.
|
||
LOOP_START is the first insn of the loop, and END is the end insn. */
|
||
|
||
static void
|
||
check_eliminate_biv (bl, loop_start, end)
|
||
struct iv_class *bl;
|
||
rtx loop_start;
|
||
rtx end;
|
||
{
|
||
/* Get the REG rtx for the biv. */
|
||
rtx reg = SET_DEST (PATTERN (bl->biv->insn));
|
||
rtx p;
|
||
struct induction *v;
|
||
|
||
bl->eliminable = 0;
|
||
|
||
for (p = loop_start; p != end; p = NEXT_INSN (p))
|
||
{
|
||
enum rtx_code code = GET_CODE (p);
|
||
if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
|
||
&& reg_mentioned_p (reg, PATTERN (p)))
|
||
{
|
||
/* This insn uses the biv. If we can't understand it,
|
||
then we can't eliminate the biv. */
|
||
if (GET_CODE (PATTERN (p)) != SET)
|
||
{
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream,
|
||
"Cannot eliminate biv %d: cannot understand insn %d.\n",
|
||
bl->regno, INSN_UID (p));
|
||
break;
|
||
}
|
||
|
||
/* The insns that increment the biv are no problem. */
|
||
if (SET_DEST (PATTERN (p)) == reg)
|
||
continue;
|
||
|
||
/* If this is an insn which uses the biv ONLY in the
|
||
calculation of a giv which is in the family of this
|
||
biv, it's ok becuase it will go away when the giv is
|
||
reduced. March 14, 1989 -- self@bayes.arc.nasa.gov */
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (v->insn == p)
|
||
{
|
||
if (v->giv_type == DEST_REG
|
||
|| (v->giv_type == DEST_ADDR
|
||
&& ! only_reg_use_p (reg, *(v->location),
|
||
PATTERN (p))))
|
||
break;
|
||
}
|
||
if (v)
|
||
continue;
|
||
|
||
/* If can rewrite this insn not to use the biv, it's ok. */
|
||
if (can_eliminate_biv_p (p, bl))
|
||
continue;
|
||
|
||
/* Biv is used in a way we cannot eliminate. */
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream,
|
||
"Cannot eliminate biv %d: biv used in insn %d.\n",
|
||
bl->regno, INSN_UID (p));
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p == end)
|
||
{
|
||
bl->eliminable = 1;
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Can eliminate biv %d.\n",
|
||
bl->regno);
|
||
}
|
||
}
|
||
|
||
/* Return 1 if INSN, a compare insn which tests the biv described by BL,
|
||
can be rewritten to use instead some reduced giv related to that biv.
|
||
Does not change the rtl.
|
||
|
||
We make the assumption that all the givs depending on this biv
|
||
will be reduced, since only in that case will an attempt to eliminate
|
||
the biv actually be made.
|
||
|
||
The following function is very parallel to this one. */
|
||
|
||
static int
|
||
can_eliminate_biv_p (insn, bl)
|
||
rtx insn;
|
||
struct iv_class *bl;
|
||
{
|
||
rtx src;
|
||
enum rtx_code code;
|
||
struct induction *v, *tv;
|
||
rtx arg;
|
||
int arg_operand;
|
||
/* Mode of this biv. */
|
||
enum machine_mode mode = bl->biv->mode;
|
||
|
||
if (SET_DEST (PATTERN (insn)) != cc0_rtx)
|
||
return 0;
|
||
|
||
src = SET_SRC (PATTERN (insn));
|
||
code = GET_CODE (src);
|
||
|
||
switch (code)
|
||
{
|
||
/* a test insn */
|
||
case REG:
|
||
/* Can replace with any giv that has (MULT_VAL != 0) and (ADD_VAL == 0)
|
||
Require a constant integer for MULT_VAL, so we know it's nonzero. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT && v->mult_val != const0_rtx
|
||
&& v->add_val == const0_rtx
|
||
&& ! v->ignore
|
||
&& v->mode == mode)
|
||
return 1;
|
||
|
||
/* Look for a giv with (MULT_VAL != 0) and (ADD_VAL != 0);
|
||
replace test insn with a compare insn (cmp REDUCED_GIV ADD_VAL).
|
||
Require a constant integer for MULT_VAL, so we know it's nonzero. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT && v->mult_val != const0_rtx
|
||
&& ! v->ignore
|
||
&& v->mode == mode)
|
||
return 1;
|
||
|
||
if (loop_dump_stream)
|
||
fprintf (loop_dump_stream, "Cannot eliminate biv %d in test insn %d: no appropriate giv.\n",
|
||
bl->regno, INSN_UID (insn));
|
||
|
||
return 0;
|
||
|
||
/* a compare insn */
|
||
case COMPARE:
|
||
/* Figure out which operand is the biv. */
|
||
if ((GET_CODE (XEXP (src, 0)) == REG)
|
||
&& (REGNO (XEXP (src, 0)) == bl->regno))
|
||
{
|
||
arg = XEXP (src, 1);
|
||
arg_operand = 1;
|
||
}
|
||
else
|
||
{
|
||
arg = XEXP (src, 0);
|
||
arg_operand = 0;
|
||
}
|
||
|
||
if (GET_CODE (arg) == CONST_INT)
|
||
{
|
||
/* Can replace with any giv that has constant coefficients. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT
|
||
&& GET_CODE (v->add_val) == CONST_INT
|
||
&& ! v->ignore
|
||
&& v->mode == mode)
|
||
return 1;
|
||
|
||
/* Look for giv with constant mult_val and nonconst add_val,
|
||
since we can insert add insn before loop
|
||
to calculate new compare value. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT
|
||
&& ! v->ignore
|
||
&& v->mode == mode)
|
||
return 1;
|
||
}
|
||
else if (GET_CODE (arg) == REG || GET_CODE (arg) == MEM)
|
||
{
|
||
/* Comparing against invariant register or memref can be handled. */
|
||
|
||
if (invariant_p (arg))
|
||
{
|
||
/* Look for giv with constant mult_val and nonconst add_val.
|
||
Insert add-insn before loop to compute new compare value. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if ((GET_CODE (v->mult_val) == CONST_INT)
|
||
&& ! v->ignore
|
||
&& v->mode == mode)
|
||
return 1;
|
||
}
|
||
|
||
/* Otherwise, only comparing against a biv can be handled. */
|
||
if (GET_CODE (arg) != REG
|
||
|| induct_var[REGNO (arg)] != BASIC_INDUCT)
|
||
return 0;
|
||
|
||
/* Look for a giv for each biv that have identical
|
||
values for mult_val and add_val. */
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (v->mode == mode
|
||
&& ! v->ignore)
|
||
{
|
||
for (tv = class_struct[REGNO (arg)]->giv; tv; tv = tv->family)
|
||
if ((tv->new_reg != 0)
|
||
&& rtx_equal_p (tv->mult_val, v->mult_val)
|
||
&& rtx_equal_p (tv->mult_val, v->mult_val)
|
||
&& ! tv->ignore
|
||
&& tv->mode == mode)
|
||
return 1;
|
||
}
|
||
}
|
||
return 0;
|
||
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/* Rewrite a compare insn INSN which uses the biv described by BL
|
||
so that it doesn't use that biv any more.
|
||
Instead it will use some reduced giv related to that biv.
|
||
|
||
The preceding function is very parallel to this one. */
|
||
|
||
static void
|
||
eliminate_biv (insn, bl, loop_start)
|
||
rtx insn;
|
||
struct iv_class *bl;
|
||
rtx loop_start;
|
||
{
|
||
rtx src = SET_SRC (PATTERN (insn));
|
||
enum rtx_code code = GET_CODE (src);
|
||
struct induction *v, *tv;
|
||
rtx arg;
|
||
int arg_operand;
|
||
/* Mode of this biv. */
|
||
enum machine_mode mode = bl->biv->mode;
|
||
|
||
switch (code)
|
||
{
|
||
/* a test insn */
|
||
case REG:
|
||
/* Can replace with any giv that was reduced and
|
||
that has (MULT_VAL != 0) and (ADD_VAL == 0).
|
||
Require a constant integer for MULT_VAL, so we know it's nonzero. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT && v->mult_val != const0_rtx
|
||
&& v->add_val == const0_rtx
|
||
&& v->new_reg != 0
|
||
&& v->mode == mode)
|
||
break;
|
||
if (v)
|
||
{
|
||
/* We can test the sign of that giv's reduced reg. */
|
||
SET_SRC (PATTERN (insn)) = v->new_reg;
|
||
return;
|
||
}
|
||
|
||
/* Look for a giv with (MULT_VAL != 0) and (ADD_VAL != 0);
|
||
replace test insn with a compare insn (cmp REDUCED_GIV ADD_VAL).
|
||
Require a constant integer for MULT_VAL, so we know it's nonzero. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT && v->mult_val != const0_rtx
|
||
&& v->new_reg != 0
|
||
&& v->mode == mode)
|
||
break;
|
||
if (v)
|
||
{
|
||
/* Replace biv with the giv's reduced register. */
|
||
SET_SRC (PATTERN (insn)) = gen_rtx (COMPARE, GET_MODE (v->new_reg),
|
||
v->new_reg,
|
||
copy_rtx (v->add_val));
|
||
|
||
#if 0
|
||
/* add_val must be invariant, so don't bother storing in a register */
|
||
/* calculate the appropriate constant to compare against */
|
||
emit_insn_before (gen_rtx (SET, VOIDmode, compare_value,
|
||
copy_rtx (v->add_val)),
|
||
loop_start);
|
||
#endif
|
||
return;
|
||
}
|
||
abort ();
|
||
break;
|
||
|
||
/* a compare insn */
|
||
case COMPARE:
|
||
/* Figure out which operand is the biv. */
|
||
if (GET_CODE (XEXP (src, 0)) == REG
|
||
&& REGNO (XEXP (src, 0)) == bl->regno)
|
||
{
|
||
arg = XEXP (src, 1);
|
||
arg_operand = 1;
|
||
}
|
||
else
|
||
{
|
||
arg = XEXP (src, 0);
|
||
arg_operand = 0;
|
||
}
|
||
|
||
if (GET_CODE (arg) == CONST_INT)
|
||
{
|
||
/* Can replace with any giv that has constant mult_val and add_val.
|
||
Make sure it was strength reduced by checking new_reg != 0. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT
|
||
&& GET_CODE (v->add_val) == CONST_INT
|
||
&& v->new_reg
|
||
&& v->mode == mode)
|
||
break;
|
||
if (v)
|
||
{
|
||
rtx newval;
|
||
/* Replace biv with the giv's reduced reg. */
|
||
XEXP (src, 1-arg_operand) = v->new_reg;
|
||
/* Calculate the appropriate constant to compare against. */
|
||
newval = gen_rtx (CONST_INT, VOIDmode,
|
||
(INTVAL (arg) * INTVAL (v->mult_val)
|
||
+ INTVAL (v->add_val)));
|
||
XEXP (src, arg_operand) = newval;
|
||
/* If that constant is no good in a compare,
|
||
put it in a register. */
|
||
if (recog (PATTERN (insn), insn) < 0)
|
||
{
|
||
rtx temp = gen_reg_rtx (mode);
|
||
emit_iv_init_code (arg, v->mult_val, v->add_val,
|
||
temp, loop_start);
|
||
XEXP (src, arg_operand) = temp;
|
||
}
|
||
return;
|
||
}
|
||
|
||
/* Look for giv with constant mult_val and nonconst add_val.
|
||
Insert add insn before loop to calculate new compare value. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT
|
||
&& v->new_reg
|
||
&& v->mode == mode)
|
||
break;
|
||
if (v)
|
||
{
|
||
rtx compare_value = gen_reg_rtx (mode);
|
||
|
||
/* Replace biv with giv's reduced register. */
|
||
XEXP (src, 1-arg_operand) = v->new_reg;
|
||
|
||
/* At start of loop, compute value to compare against. */
|
||
emit_iv_init_code (arg, v->mult_val, v->add_val,
|
||
compare_value, loop_start);
|
||
/* Use it in this insn. */
|
||
XEXP (src, arg_operand) = compare_value;
|
||
return;
|
||
}
|
||
abort ();
|
||
}
|
||
else if (GET_CODE (arg) == REG || GET_CODE (arg) == MEM)
|
||
{
|
||
if (invariant_p (arg))
|
||
{
|
||
/* Look for giv with constant mult_val and nonconst add_val.
|
||
Insert add-insn before loop to compute new compare value. */
|
||
|
||
for (v = bl->giv; v; v = v->family)
|
||
if (GET_CODE (v->mult_val) == CONST_INT
|
||
&& v->new_reg
|
||
&& v->mode == mode)
|
||
break;
|
||
if (v)
|
||
{
|
||
rtx compare_value = gen_reg_rtx (mode);
|
||
|
||
/* Replace biv with giv's reduced register. */
|
||
XEXP (src, 1-arg_operand) = v->new_reg;
|
||
|
||
/* At start of loop, compute value to compare against. */
|
||
emit_iv_init_code (arg, v->mult_val, v->add_val,
|
||
compare_value, loop_start);
|
||
XEXP (src, arg_operand) = compare_value;
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* Otherwise the reg compared with had better be a biv. */
|
||
if (GET_CODE (arg) != REG
|
||
|| induct_var[REGNO (arg)] != BASIC_INDUCT)
|
||
abort ();
|
||
|
||
/* Look for a pair of givs, one for each biv,
|
||
with identical coefficients. */
|
||
for (v = bl->giv; v; v = v->family)
|
||
{
|
||
if (!v->new_reg && v->mode == mode)
|
||
continue;
|
||
for (tv = class_struct[REGNO (arg)]->giv; tv; tv = tv->family)
|
||
if ((tv->new_reg != 0)
|
||
&& rtx_equal_p (tv->mult_val, v->mult_val)
|
||
&& rtx_equal_p (tv->mult_val, v->mult_val)
|
||
&& tv->mode == mode)
|
||
break;
|
||
if (tv)
|
||
break;
|
||
}
|
||
if (v)
|
||
{
|
||
/* Replace biv with its giv's reduced reg. */
|
||
XEXP (src, 1-arg_operand) = v->new_reg;
|
||
/* Replace other operand with the other giv's reduced reg. */
|
||
XEXP (src, arg_operand) = tv->new_reg;
|
||
return;
|
||
}
|
||
}
|
||
abort ();
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
}
|
||
|
||
/* Try to calculate the final value of the biv,
|
||
the value it will have at the end of the loop.
|
||
If we can do it, return that value. */
|
||
|
||
/* ??? One case that should be simple to handle
|
||
is when the biv is incremented by an invariant
|
||
exactly once each time around the loop,
|
||
and when the number of iterations can be determined
|
||
(as the value of some invariant).
|
||
Then the final value would be BIV + (INCREMENT * NUM_ITERATIONS).
|
||
|
||
Once that case is handled, it would become desirable to detect empty
|
||
loops and delete them, since this optimization could make empty loops. */
|
||
|
||
static rtx
|
||
final_biv_value (bl, loop_end)
|
||
struct iv_class *bl;
|
||
rtx loop_end;
|
||
{
|
||
/* wimpy, but guaranteed to work */
|
||
return 0;
|
||
}
|
||
|
||
/* Return nonzero if the last use of reg REGNO
|
||
is in an insn following INSN in the same basic block. */
|
||
|
||
static int
|
||
last_use_this_basic_block (regno, insn)
|
||
int regno;
|
||
rtx insn;
|
||
{
|
||
rtx n;
|
||
for (n = insn;
|
||
n && GET_CODE (n) != CODE_LABEL && GET_CODE (n) != JUMP_INSN;
|
||
n = NEXT_INSN (n))
|
||
{
|
||
if (regno_last_uid[regno] == INSN_UID (n))
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|