Commit d9e7c8e3 by Roger Sayle Committed by Roger Sayle

re PR rtl-optimization/11634 ([hppa] ICE in verify_local_live_at_start, at flow.c:555)


	PR optimization/11634
	* recog.c (split_insn): Factor test of INSN_P and handling of
	set_noop_p out of here into the two callers.
	(split_all_insns): Add INSN_P test and set_noop_p handling here.
	If deleting a no-op set after reload that has a REG_UNUSED note,
	mark the basic block as changed and recalculate life information.
	(split_all_insns_noflow): Add INSN_P test and set_noop_p handling
	here.

	* gcc.dg/20031201-2.c: New test case.

From-SVN: r74145
parent b58b21d5
2003-12-01 Roger Sayle <roger@eyesopen.com> 2003-12-01 Roger Sayle <roger@eyesopen.com>
PR optimization/11634
* recog.c (split_insn): Factor test of INSN_P and handling of
set_noop_p out of here into the two callers.
(split_all_insns): Add INSN_P test and set_noop_p handling here.
If deleting a no-op set after reload that has a REG_UNUSED note,
mark the basic block as changed and recalculate life information.
(split_all_insns_noflow): Add INSN_P test and set_noop_p handling
here.
2003-12-01 Roger Sayle <roger@eyesopen.com>
PR optimization/12322 PR optimization/12322
* gcse.c (struct ls_expr): Change type of hash_index from int to * gcse.c (struct ls_expr): Change type of hash_index from int to
unsigned int. unsigned int.
......
...@@ -2642,61 +2642,42 @@ reg_fits_class_p (rtx operand, enum reg_class class, int offset, ...@@ -2642,61 +2642,42 @@ reg_fits_class_p (rtx operand, enum reg_class class, int offset,
return 0; return 0;
} }
/* Split single instruction. Helper function for split_all_insns. /* Split single instruction. Helper function for split_all_insns and
Return last insn in the sequence if successful, or NULL if unsuccessful. */ split_all_insns_noflow. Return last insn in the sequence if successful,
or NULL if unsuccessful. */
static rtx static rtx
split_insn (rtx insn) split_insn (rtx insn)
{ {
rtx set; /* Split insns here to get max fine-grain parallelism. */
if (!INSN_P (insn)) rtx first = PREV_INSN (insn);
; rtx last = try_split (PATTERN (insn), insn, 1);
/* Don't split no-op move insns. These should silently
disappear later in final. Splitting such insns would
break the code that handles REG_NO_CONFLICT blocks. */
else if ((set = single_set (insn)) != NULL && set_noop_p (set)) if (last == insn)
{ return NULL_RTX;
/* Nops get in the way while scheduling, so delete them
now if register allocation has already been done. It /* try_split returns the NOTE that INSN became. */
is too risky to try to do this before register PUT_CODE (insn, NOTE);
allocation, and there are unlikely to be very many NOTE_SOURCE_FILE (insn) = 0;
nops then anyways. */ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
if (reload_completed)
delete_insn_and_edges (insn);
}
else
{
/* Split insns here to get max fine-grain parallelism. */
rtx first = PREV_INSN (insn);
rtx last = try_split (PATTERN (insn), insn, 1);
if (last != insn) /* ??? Coddle to md files that generate subregs in post-reload
splitters instead of computing the proper hard register. */
if (reload_completed && first != last)
{
first = NEXT_INSN (first);
for (;;)
{ {
/* try_split returns the NOTE that INSN became. */ if (INSN_P (first))
PUT_CODE (insn, NOTE); cleanup_subreg_operands (first);
NOTE_SOURCE_FILE (insn) = 0; if (first == last)
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; break;
first = NEXT_INSN (first);
/* ??? Coddle to md files that generate subregs in post-
reload splitters instead of computing the proper
hard register. */
if (reload_completed && first != last)
{
first = NEXT_INSN (first);
while (1)
{
if (INSN_P (first))
cleanup_subreg_operands (first);
if (first == last)
break;
first = NEXT_INSN (first);
}
}
return last;
} }
} }
return NULL_RTX; return last;
} }
/* Split all insns in the function. If UPD_LIFE, update life info after. */ /* Split all insns in the function. If UPD_LIFE, update life info after. */
void void
...@@ -2717,24 +2698,52 @@ split_all_insns (int upd_life) ...@@ -2717,24 +2698,52 @@ split_all_insns (int upd_life)
for (insn = bb->head; !finish ; insn = next) for (insn = bb->head; !finish ; insn = next)
{ {
rtx last;
/* Can't use `next_real_insn' because that might go across /* Can't use `next_real_insn' because that might go across
CODE_LABELS and short-out basic blocks. */ CODE_LABELS and short-out basic blocks. */
next = NEXT_INSN (insn); next = NEXT_INSN (insn);
finish = (insn == bb->end); finish = (insn == bb->end);
last = split_insn (insn); if (INSN_P (insn))
if (last)
{ {
/* The split sequence may include barrier, but the rtx set = single_set (insn);
BB boundary we are interested in will be set to previous
one. */ /* Don't split no-op move insns. These should silently
disappear later in final. Splitting such insns would
while (GET_CODE (last) == BARRIER) break the code that handles REG_NO_CONFLICT blocks. */
last = PREV_INSN (last); if (set && set_noop_p (set))
SET_BIT (blocks, bb->index); {
changed = true; /* Nops get in the way while scheduling, so delete them
insn = last; now if register allocation has already been done. It
is too risky to try to do this before register
allocation, and there are unlikely to be very many
nops then anyways. */
if (reload_completed)
{
/* If the no-op set has a REG_UNUSED note, we need
to update liveness information. */
if (find_reg_note (insn, REG_UNUSED, NULL_RTX))
{
SET_BIT (blocks, bb->index);
changed = true;
}
/* ??? Is life info affected by deleting edges? */
delete_insn_and_edges (insn);
}
}
else
{
rtx last = split_insn (insn);
if (last)
{
/* The split sequence may include barrier, but the
BB boundary we are interested in will be set to
previous one. */
while (GET_CODE (last) == BARRIER)
last = PREV_INSN (last);
SET_BIT (blocks, bb->index);
changed = true;
}
}
} }
} }
} }
...@@ -2771,9 +2780,28 @@ split_all_insns_noflow (void) ...@@ -2771,9 +2780,28 @@ split_all_insns_noflow (void)
for (insn = get_insns (); insn; insn = next) for (insn = get_insns (); insn; insn = next)
{ {
next = NEXT_INSN (insn); next = NEXT_INSN (insn);
split_insn (insn); if (INSN_P (insn))
{
/* Don't split no-op move insns. These should silently
disappear later in final. Splitting such insns would
break the code that handles REG_NO_CONFLICT blocks. */
rtx set = single_set (insn);
if (set && set_noop_p (set))
{
/* Nops get in the way while scheduling, so delete them
now if register allocation has already been done. It
is too risky to try to do this before register
allocation, and there are unlikely to be very many
nops then anyways.
??? Should we use delete_insn when the CFG isn't valid? */
if (reload_completed)
delete_insn_and_edges (insn);
}
else
split_insn (insn);
}
} }
return;
} }
#ifdef HAVE_peephole2 #ifdef HAVE_peephole2
......
2003-12-01 Roger Sayle <roger@eyesopen.com>
PR optimization/11634
* gcc.dg/20031201-2.c: New test case.
2003-12-01 Zack Weinberg <zack@codesourcery.com> 2003-12-01 Zack Weinberg <zack@codesourcery.com>
PR 11433 PR 11433
......
/* PR optimization/11634 */
/* The following code used to ICE in verify_local_live_at_start on
PA when compiled with -O2. The cause was that split_all_insns was
not updating liveness information when deleting no-op moves that
had REG_UNUSED notes. */
/* { dg-do compile { target hppa*-*-* } } */
/* { dg-options "-O2" } */
void *f(void *s);
void H5T_conv_vlen (unsigned long long nelmts, unsigned char *bg_ptr)
{
long long seq_len;
unsigned long long bg_seq_len = 0;
unsigned src_base_size, dst_base_size;
void *tmp_buf = 0;
unsigned tmp_buf_size = 0;
unsigned long long elmtno;
for (elmtno = 0; elmtno < nelmts; elmtno++)
{
unsigned char *tmp = bg_ptr;
bg_seq_len = *tmp;
if (bg_seq_len > 0
&& tmp_buf_size <
(unsigned) (bg_seq_len *
(src_base_size > dst_base_size
? src_base_size
: dst_base_size)))
{
tmp_buf_size =
(unsigned) (bg_seq_len *
(src_base_size > dst_base_size
? src_base_size
: dst_base_size));
}
if (bg_seq_len < seq_len)
f ((unsigned char *) tmp_buf + dst_base_size * bg_seq_len);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment