emit-rtl.c (subreg_hard_regno): Check that register is representable.
* emit-rtl.c (subreg_hard_regno): Check that register is representable. * reload.c (reload_inner_reg_of_subreg): When register is not representable, reload the whole thing. (find_reloads): Likewsie. * rtlanal.c (subreg_representable_p): New function. * profile.c (compute_branch_probabilities): Cleanup sanity checking; allow negative probabilities for edges from the call to exit. (branch_prob): Do not add fake edges for functions that may return twice From-SVN: r65757
This commit is contained in:
parent
c409ea0d30
commit
04c5580f37
6 changed files with 155 additions and 61 deletions
|
@ -1,3 +1,15 @@
|
|||
Fri Apr 18 01:28:51 CEST 2003 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* emit-rtl.c (subreg_hard_regno): Check that register is representable.
|
||||
* reload.c (reload_inner_reg_of_subreg): When register is not
|
||||
representable, reload the whole thing.
|
||||
(find_reloads): Likewsie.
|
||||
* rtlanal.c (subreg_representable_p): New function.
|
||||
|
||||
* profile.c (compute_branch_probabilities): Cleanup sanity checking;
|
||||
allow negative probabilities for edges from the call to exit.
|
||||
(branch_prob): Do not add fake edges for functions that may return twice
|
||||
|
||||
2003-04-17 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* toplev.c (target_options): Add value field.
|
||||
|
|
|
@ -1081,7 +1081,11 @@ subreg_hard_regno (x, check_mode)
|
|||
abort ();
|
||||
if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
|
||||
abort ();
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
|
||||
SUBREG_BYTE (x), mode))
|
||||
abort ();
|
||||
#endif
|
||||
/* Catch non-congruent offsets too. */
|
||||
byte_offset = SUBREG_BYTE (x);
|
||||
if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
|
||||
|
|
|
@ -674,22 +674,47 @@ compute_branch_probabilities ()
|
|||
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
|
||||
{
|
||||
edge e;
|
||||
gcov_type total;
|
||||
rtx note;
|
||||
|
||||
total = bb->count;
|
||||
if (total)
|
||||
if (bb->count < 0)
|
||||
{
|
||||
error ("corrupted profile info: number of iterations for basic block %d thought to be %i",
|
||||
bb->index, (int)bb->count);
|
||||
bb->count = 0;
|
||||
}
|
||||
for (e = bb->succ; e; e = e->succ_next)
|
||||
{
|
||||
/* Function may return twice in the cased the called fucntion is
|
||||
setjmp or calls fork, but we can't represent this by extra
|
||||
edge from the entry, since extra edge from the exit is
|
||||
already present. We get negative frequency from the entry
|
||||
point. */
|
||||
if ((e->count < 0
|
||||
&& e->dest == EXIT_BLOCK_PTR)
|
||||
|| (e->count > bb->count
|
||||
&& e->dest != EXIT_BLOCK_PTR))
|
||||
{
|
||||
rtx insn = bb->end;
|
||||
|
||||
while (GET_CODE (insn) != CALL_INSN
|
||||
&& insn != bb->head
|
||||
&& keep_with_call_p (insn))
|
||||
insn = PREV_INSN (insn);
|
||||
if (GET_CODE (insn) == CALL_INSN)
|
||||
e->count = e->count < 0 ? 0 : bb->count;
|
||||
}
|
||||
if (e->count < 0 || e->count > bb->count)
|
||||
{
|
||||
error ("corrupted profile info: number of executions for edge %d-%d thought to be %i",
|
||||
e->src->index, e->dest->index,
|
||||
(int)e->count);
|
||||
e->count = bb->count / 2;
|
||||
}
|
||||
}
|
||||
if (bb->count)
|
||||
{
|
||||
for (e = bb->succ; e; e = e->succ_next)
|
||||
{
|
||||
e->probability = (e->count * REG_BR_PROB_BASE + total / 2) / total;
|
||||
if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
|
||||
{
|
||||
error ("corrupted profile info: prob for %d-%d thought to be %d",
|
||||
e->src->index, e->dest->index, e->probability);
|
||||
e->probability = REG_BR_PROB_BASE / 2;
|
||||
}
|
||||
}
|
||||
e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count;
|
||||
if (bb->index >= 0
|
||||
&& any_condjump_p (bb->end)
|
||||
&& bb->succ->succ_next)
|
||||
|
@ -730,6 +755,8 @@ compute_branch_probabilities ()
|
|||
calls). */
|
||||
else
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (e = bb->succ; e; e = e->succ_next)
|
||||
if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
|
||||
total ++;
|
||||
|
@ -873,36 +900,13 @@ branch_prob ()
|
|||
{
|
||||
int need_exit_edge = 0, need_entry_edge = 0;
|
||||
int have_exit_edge = 0, have_entry_edge = 0;
|
||||
rtx insn;
|
||||
edge e;
|
||||
|
||||
/* Add fake edges from entry block to the call insns that may return
|
||||
twice. The CFG is not quite correct then, as call insn plays more
|
||||
role of CODE_LABEL, but for our purposes, everything should be OK,
|
||||
as we never insert code to the beginning of basic block. */
|
||||
for (insn = bb->head; insn != NEXT_INSN (bb->end);
|
||||
insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == CALL_INSN
|
||||
&& find_reg_note (insn, REG_SETJMP, NULL))
|
||||
{
|
||||
if (GET_CODE (bb->head) == CODE_LABEL
|
||||
|| insn != NEXT_INSN (bb->head))
|
||||
{
|
||||
e = split_block (bb, PREV_INSN (insn));
|
||||
make_edge (ENTRY_BLOCK_PTR, e->dest, EDGE_FAKE);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We should not get abort here, as call to setjmp should not
|
||||
be the very first instruction of function. */
|
||||
if (bb == ENTRY_BLOCK_PTR)
|
||||
abort ();
|
||||
make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Functions returning multiple times are not handled by extra edges.
|
||||
Instead we simply allow negative counts on edges from exit to the
|
||||
block past call and corresponding probabilities. We can't go
|
||||
with the extra edges because that would result in flowgraph that
|
||||
needs to have fake edges outside the spanning tree. */
|
||||
|
||||
for (e = bb->succ; e; e = e->succ_next)
|
||||
{
|
||||
|
|
39
gcc/reload.c
39
gcc/reload.c
|
@ -2880,6 +2880,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
|||
if (GET_CODE (SUBREG_REG (operand)) == REG
|
||||
&& REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
if (!subreg_offset_representable_p
|
||||
(REGNO (SUBREG_REG (operand)),
|
||||
GET_MODE (SUBREG_REG (operand)),
|
||||
SUBREG_BYTE (operand),
|
||||
GET_MODE (operand)))
|
||||
force_reload = 1;
|
||||
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
|
||||
GET_MODE (SUBREG_REG (operand)),
|
||||
SUBREG_BYTE (operand),
|
||||
|
@ -2935,26 +2941,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|
|||
)
|
||||
#endif
|
||||
)
|
||||
/* This following hunk of code should no longer be
|
||||
needed at all with SUBREG_BYTE. If you need this
|
||||
code back, please explain to me why so I can
|
||||
fix the real problem. -DaveM */
|
||||
#if 0
|
||||
/* Subreg of a hard reg which can't handle the subreg's mode
|
||||
or which would handle that mode in the wrong number of
|
||||
registers for subregging to work. */
|
||||
|| (GET_CODE (operand) == REG
|
||||
&& REGNO (operand) < FIRST_PSEUDO_REGISTER
|
||||
&& ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
|
||||
&& (GET_MODE_SIZE (GET_MODE (operand))
|
||||
> UNITS_PER_WORD)
|
||||
&& ((GET_MODE_SIZE (GET_MODE (operand))
|
||||
/ UNITS_PER_WORD)
|
||||
!= HARD_REGNO_NREGS (REGNO (operand),
|
||||
GET_MODE (operand))))
|
||||
|| ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
|
||||
operand_mode[i])))
|
||||
#endif
|
||||
)
|
||||
force_reload = 1;
|
||||
}
|
||||
|
@ -5272,6 +5258,19 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
|
|||
SUBREG_BYTE (orig_op1),
|
||||
GET_MODE (orig_op1))));
|
||||
}
|
||||
/* Plus in the index register may be created only as a result of
|
||||
register remateralization for expresion like &localvar*4. Reload it.
|
||||
It may be possible to combine the displacement on the outer level,
|
||||
but it is probably not worthwhile to do so. */
|
||||
if (context)
|
||||
{
|
||||
find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
|
||||
opnum, ADDR_TYPE (type), ind_levels, insn);
|
||||
push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
|
||||
(context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
|
||||
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|
||||
|| code0 == ZERO_EXTEND || code1 == MEM)
|
||||
|
|
|
@ -1038,6 +1038,10 @@ extern unsigned int subreg_regno_offset PARAMS ((unsigned int,
|
|||
enum machine_mode,
|
||||
unsigned int,
|
||||
enum machine_mode));
|
||||
extern bool subreg_offset_representable_p PARAMS ((unsigned int,
|
||||
enum machine_mode,
|
||||
unsigned int,
|
||||
enum machine_mode));
|
||||
extern unsigned int subreg_regno PARAMS ((rtx));
|
||||
|
||||
/* 1 if RTX is a subreg containing a reg that is already known to be
|
||||
|
|
|
@ -3387,6 +3387,77 @@ subreg_regno_offset (xregno, xmode, offset, ymode)
|
|||
return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
|
||||
}
|
||||
|
||||
/* This function returns true when the offset is representable via
|
||||
subreg_offset in the given regno.
|
||||
xregno - A regno of an inner hard subreg_reg (or what will become one).
|
||||
xmode - The mode of xregno.
|
||||
offset - The byte offset.
|
||||
ymode - The mode of a top level SUBREG (or what may become one).
|
||||
RETURN - The regno offset which would be used. */
|
||||
bool
|
||||
subreg_offset_representable_p (xregno, xmode, offset, ymode)
|
||||
unsigned int xregno;
|
||||
enum machine_mode xmode;
|
||||
unsigned int offset;
|
||||
enum machine_mode ymode;
|
||||
{
|
||||
int nregs_xmode, nregs_ymode;
|
||||
int mode_multiple, nregs_multiple;
|
||||
int y_offset;
|
||||
|
||||
if (xregno >= FIRST_PSEUDO_REGISTER)
|
||||
abort ();
|
||||
|
||||
nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
|
||||
nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
|
||||
|
||||
/* paradoxical subregs are always valid. */
|
||||
if (offset == 0
|
||||
&& nregs_ymode > nregs_xmode
|
||||
&& (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
|
||||
? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
|
||||
return true;
|
||||
|
||||
/* Lowpart subregs are always valid. */
|
||||
if (offset == subreg_lowpart_offset (ymode, xmode))
|
||||
return true;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* This should always pass, otherwise we don't know how to verify the
|
||||
constraint.
|
||||
|
||||
These conditions may be relaxed but subreg_offset would need to be
|
||||
redesigned. */
|
||||
if (GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)
|
||||
|| GET_MODE_SIZE (ymode) % nregs_ymode
|
||||
|| mode_for_size (GET_MODE_SIZE (ymode) / nregs_ymode,
|
||||
MODE_INT, 0) == VOIDmode
|
||||
|| nregs_xmode % nregs_ymode)
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
/* The XMODE value can be seen as an vector of NREGS_XMODE
|
||||
values. The subreg must represent an lowpart of given field.
|
||||
Compute what field it is. */
|
||||
offset -= subreg_lowpart_offset (mode_for_size (GET_MODE_SIZE (ymode)
|
||||
/ nregs_ymode,
|
||||
MODE_INT, 0), xmode);
|
||||
|
||||
/* size of ymode must not be greater than the size of xmode. */
|
||||
mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
|
||||
if (mode_multiple == 0)
|
||||
abort ();
|
||||
|
||||
y_offset = offset / GET_MODE_SIZE (ymode);
|
||||
nregs_multiple = nregs_xmode / nregs_ymode;
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (offset % GET_MODE_SIZE (ymode)
|
||||
|| mode_multiple % nregs_multiple)
|
||||
abort ();
|
||||
#endif
|
||||
return (!(y_offset % (mode_multiple / nregs_multiple)));
|
||||
}
|
||||
|
||||
/* Return the final regno that a subreg expression refers to. */
|
||||
unsigned int
|
||||
subreg_regno (x)
|
||||
|
|
Loading…
Add table
Reference in a new issue