This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
reg-stack strikes back II
- To: rth at cygnus dot com, gcc-patches at gcc dot gnu dot org
- Subject: reg-stack strikes back II
- From: Jan Hubicka <jh at suse dot cz>
- Date: Thu, 7 Jun 2001 16:53:40 +0200
Hi,
unfortunately the previous patch didn't fix the problem.
The split_all_insns already has code to deal with broken flowgraph, since it is
used after reload, but it is rather humorous - it simply allows loops to drop
off basic block to the end. That has potential to bring problem, as deleted
instruction may be traversed.
I've fixed it by making split_insn independent on basic block information
if upd_info is 0.
This fixes all problems I am seeing, but in case I will not get response
until mips bootstrap finishes (i386/sparc already did), I will probably
revert my last toplev.c patch and wait for approval with this one before
installing it back.
I apologize for so frequent breakage this day :(
Really hope it will not repreat
Honza
Thu Jun 7 16:48:39 CEST 2001 Jan Hubicka <jh@suse.cz>
* recog.c (split_insn): Break out from ...
(split_all_insns): ... here; do not use basic block information
when it is broken.
Index: recog.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/recog.c,v
retrieving revision 1.105
diff -c -3 -p -r1.105 recog.c
*** recog.c 2001/05/22 06:46:20 1.105
--- recog.c 2001/06/07 14:42:59
*************** static void validate_replace_rtx_1 PARAM
*** 57,62 ****
--- 57,63 ----
static rtx *find_single_use_1 PARAMS ((rtx, rtx *));
static rtx *find_constant_term_loc PARAMS ((rtx *));
static void validate_replace_src_1 PARAMS ((rtx *, void *));
+ static rtx split_insn PARAMS ((rtx));
/* Nonzero means allow operands to be volatile.
This should be 0 if you are generating rtl, such as if you are calling
*************** reg_fits_class_p (operand, class, offset
*** 2700,2705 ****
--- 2701,2766 ----
return 0;
}
+ /* Split single instruction. Helper function for split_all_insns.
+ Return last insn in the sequence if succesfull, or NULL if unsuccesfull. */
+ static rtx
+ split_insn (insn)
+ rtx insn;
+ {
+ rtx set;
+ 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. */
+
+ else if ((set = single_set (insn)) != NULL && 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. */
+ if (reload_completed)
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ }
+ }
+ 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)
+ {
+ /* try_split returns the NOTE that INSN became. */
+ PUT_CODE (insn, NOTE);
+ NOTE_SOURCE_FILE (insn) = 0;
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+
+ /* ??? 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;
+ }
/* Split all insns in the function. If UPD_LIFE, update life info after. */
void
*************** split_all_insns (upd_life)
*** 2710,2715 ****
--- 2771,2792 ----
int changed;
int i;
+ if (!upd_life)
+ {
+ rtx next, insn;
+
+ for (insn = get_insns (); insn ; insn = next)
+ {
+ rtx last;
+
+ /* Can't use `next_real_insn' because that might go across
+ CODE_LABELS and short-out basic blocks. */
+ next = NEXT_INSN (insn);
+ last = split_insn (insn);
+ }
+ return;
+ }
+
blocks = sbitmap_alloc (n_basic_blocks);
sbitmap_zero (blocks);
changed = 0;
*************** split_all_insns (upd_life)
*** 2721,2791 ****
for (insn = bb->head; insn ; insn = next)
{
! rtx set;
/* Can't use `next_real_insn' because that might go across
CODE_LABELS and short-out basic blocks. */
next = NEXT_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. */
!
! else if ((set = single_set (insn)) != NULL
! && 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. */
! if (reload_completed)
! {
! PUT_CODE (insn, NOTE);
! NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
! NOTE_SOURCE_FILE (insn) = 0;
! }
! }
! 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)
! {
! SET_BIT (blocks, i);
! changed = 1;
!
! /* try_split returns the NOTE that INSN became. */
! PUT_CODE (insn, NOTE);
! NOTE_SOURCE_FILE (insn) = 0;
! NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
!
! /* ??? 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);
! }
! }
!
! if (insn == bb->end)
! {
! bb->end = last;
! break;
! }
! }
}
if (insn == bb->end)
--- 2798,2815 ----
for (insn = bb->head; insn ; insn = next)
{
! rtx last;
/* Can't use `next_real_insn' because that might go across
CODE_LABELS and short-out basic blocks. */
next = NEXT_INSN (insn);
! last = split_insn (insn);
! if (last)
{
! SET_BIT (blocks, i);
! changed = 1;
! if (insn == bb->end)
! bb->end = last;
}
if (insn == bb->end)
Index: reg-stack.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reg-stack.c,v
retrieving revision 1.76
diff -c -3 -p -r1.76 reg-stack.c
*** reg-stack.c 2001/05/01 12:11:33 1.76
--- reg-stack.c 2001/06/07 14:43:00
*************** reg_to_stack (first, file)
*** 429,435 ****
/* Ok, floating point instructions exist. If not optimizing,
build the CFG and run life analysis. */
- find_basic_blocks (first, max_reg_num (), file);
count_or_remove_death_notes (NULL, 1);
life_analysis (first, file, PROP_DEATH_NOTES);
--- 429,434 ----
Index: reload.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.c,v
retrieving revision 1.147
diff -c -3 -p -r1.147 reload.c
*** reload.c 2001/06/04 01:58:24 1.147
--- reload.c 2001/06/07 14:43:01
*************** find_reloads_toplev (x, opnum, type, ind
*** 4335,4393 ****
above should handle it). */
register int regno = REGNO (SUBREG_REG (x));
! rtx tem;
! if (subreg_lowpart_p (x)
! && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
! && reg_equiv_constant[regno] != 0
! && (tem = gen_lowpart_common (GET_MODE (x),
! reg_equiv_constant[regno])) != 0)
return tem;
- if (GET_MODE_BITSIZE (GET_MODE (x)) == BITS_PER_WORD
- && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
- && reg_equiv_constant[regno] != 0
- && (tem = operand_subword (reg_equiv_constant[regno],
- SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
- GET_MODE (SUBREG_REG (x)))) != 0)
- {
- /* TEM is now a word sized constant for the bits from X that
- we wanted. However, TEM may be the wrong representation.
-
- Use gen_lowpart_common to convert a CONST_INT into a
- CONST_DOUBLE and vice versa as needed according to by the mode
- of the SUBREG. */
- tem = gen_lowpart_common (GET_MODE (x), tem);
- if (!tem)
- abort ();
- return tem;
- }
-
- /* If the SUBREG is wider than a word, the above test will fail.
- For example, we might have a SImode SUBREG of a DImode SUBREG_REG
- for a 16 bit target, or a DImode SUBREG of a TImode SUBREG_REG for
- a 32 bit target. We still can - and have to - handle this
- for non-paradoxical subregs of CONST_INTs. */
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
- && GET_CODE (reg_equiv_constant[regno]) == CONST_INT
- && (GET_MODE_SIZE (GET_MODE (x))
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
- {
- int shift = SUBREG_BYTE (x) * BITS_PER_UNIT;
- if (WORDS_BIG_ENDIAN)
- shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
- - GET_MODE_BITSIZE (GET_MODE (x))
- - shift);
- /* Here we use the knowledge that CONST_INTs have a
- HOST_WIDE_INT field. */
- if (shift >= HOST_BITS_PER_WIDE_INT)
- shift = HOST_BITS_PER_WIDE_INT - 1;
- return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift);
- }
-
- if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
- && reg_equiv_constant[regno] != 0
&& GET_MODE (reg_equiv_constant[regno]) == VOIDmode)
abort ();
--- 4335,4351 ----
above should handle it). */
register int regno = REGNO (SUBREG_REG (x));
! rtx tem = NULL_RTX;
! if (reg_equiv_constant[regno] != 0)
! tem = simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno],
! GET_MODE (SUBREG_REG (x)),
! SUBREG_BYTE (x));
! if (tem)
return tem;
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
&& GET_MODE (reg_equiv_constant[regno]) == VOIDmode)
abort ();
*************** subst_reloads (insn)
*** 5790,5815 ****
this up. Note that r->where == &SUBREG_REG (*r->subreg_loc). */
if (r->subreg_loc != 0 && GET_CODE (reloadreg) == SUBREG)
! {
! if (GET_MODE (*r->subreg_loc)
! == GET_MODE (SUBREG_REG (reloadreg)))
! *r->subreg_loc = SUBREG_REG (reloadreg);
! else
! {
! int final_offset =
! SUBREG_BYTE (*r->subreg_loc) + SUBREG_BYTE (reloadreg);
!
! /* When working with SUBREGs the rule is that the byte
! offset must be a multiple of the SUBREG's mode. */
! final_offset = (final_offset /
! GET_MODE_SIZE (GET_MODE (*r->subreg_loc)));
! final_offset = (final_offset *
! GET_MODE_SIZE (GET_MODE (*r->subreg_loc)));
!
! *r->where = SUBREG_REG (reloadreg);
! SUBREG_BYTE (*r->subreg_loc) = final_offset;
! }
! }
else
*r->where = reloadreg;
}
--- 5748,5757 ----
this up. Note that r->where == &SUBREG_REG (*r->subreg_loc). */
if (r->subreg_loc != 0 && GET_CODE (reloadreg) == SUBREG)
! *r->subreg_loc = simplify_gen_subreg (GET_MODE (*r->subreg_loc),
! reloadreg,
! GET_MODE (reloadreg),
! SUBREG_BYTE (*r->subreg_loc));
else
*r->where = reloadreg;
}
*************** find_replacement (loc)
*** 5901,5932 ****
return reloadreg;
}
else if (reloadreg && r->subreg_loc == loc)
! {
! /* RELOADREG must be either a REG or a SUBREG.
!
! ??? Is it actually still ever a SUBREG? If so, why? */
!
! if (GET_CODE (reloadreg) == REG)
! return gen_rtx_REG (GET_MODE (*loc),
! (REGNO (reloadreg) +
! subreg_regno_offset (REGNO (SUBREG_REG (*loc)),
! GET_MODE (SUBREG_REG (*loc)),
! SUBREG_BYTE (*loc),
! GET_MODE (*loc))));
! else if (GET_MODE (reloadreg) == GET_MODE (*loc))
! return reloadreg;
! else
! {
! int final_offset = SUBREG_BYTE (reloadreg) + SUBREG_BYTE (*loc);
!
! /* When working with SUBREGs the rule is that the byte
! offset must be a multiple of the SUBREG's mode. */
! final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (*loc)));
! final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (*loc)));
! return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
! final_offset);
! }
! }
}
/* If *LOC is a PLUS, MINUS, or MULT, see if a replacement is scheduled for
--- 5843,5851 ----
return reloadreg;
}
else if (reloadreg && r->subreg_loc == loc)
! return simplify_gen_subreg (GET_MODE (*loc), reloadreg,
! GET_MODE (reloadreg),
! SUBREG_BYTE (*loc));
}
/* If *LOC is a PLUS, MINUS, or MULT, see if a replacement is scheduled for
Index: sibcall.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/sibcall.c,v
retrieving revision 1.17
diff -c -3 -p -r1.17 sibcall.c
*** sibcall.c 2001/06/04 20:20:35 1.17
--- sibcall.c 2001/06/07 14:43:01
*************** skip_use_of_return_value (orig_insn, cod
*** 220,225 ****
--- 220,254 ----
return orig_insn;
}
+ /* In case function does not return value, we get clobber of pseudo followed
+ by set to hard return value. */
+ rtx
+ skip_unreturned_value (orig_insn)
+ rtx orig_insn;
+ {
+ rtx insn = next_nonnote_insn (orig_insn);
+
+ /* Skip possible clobber of pseudo return register. */
+ if (insn
+ && GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == CLOBBER
+ && REG_P (XEXP (PATTERN (insn), 0))
+ && (REGNO (XEXP (PATTERN (insn), 0)) >= FIRST_PSEUDO_REGISTER))
+ {
+ rtx set_insn = next_nonnote_insn (insn);
+ rtx set;
+ if (!set_insn)
+ return insn;
+ set = single_set (set_insn);
+ if (!set
+ || SET_SRC (set) != XEXP (PATTERN (insn), 0)
+ || SET_DEST (set) != current_function_return_rtx)
+ return insn;
+ return set_insn;
+ }
+ return orig_insn;
+ }
+
/* If the first real insn after ORIG_INSN adjusts the stack pointer
by a constant, return the insn with the stack pointer adjustment.
Otherwise return ORIG_INSN. */
*************** call_ends_block_p (insn, end)
*** 314,319 ****
--- 343,353 ----
/* Skip over a CLOBBER of the return value as a hard reg. */
insn = skip_use_of_return_value (insn, CLOBBER);
+ if (insn == end)
+ return 1;
+
+ /* Skip over a CLOBBER of the return value as a hard reg. */
+ insn = skip_unreturned_value (insn);
if (insn == end)
return 1;
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.h,v
retrieving revision 1.186
diff -c -3 -p -r1.186 i386.h
*** i386.h 2001/06/06 12:57:31 1.186
--- i386.h 2001/06/07 14:43:04
*************** while (0)
*** 2370,2391 ****
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
- return (unsigned) INTVAL (RTX) < 256 ? 0 : 1; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
! return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 1; \
\
case CONST_DOUBLE: \
{ \
int code; \
if (GET_MODE (RTX) == VOIDmode) \
! return 2; \
\
code = standard_80387_constant_p (RTX); \
! return code == 1 ? 0 : \
! code == 2 ? 1 : \
! 2; \
}
/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
--- 2370,2390 ----
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
! return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0; \
\
case CONST_DOUBLE: \
{ \
int code; \
if (GET_MODE (RTX) == VOIDmode) \
! return 0; \
\
code = standard_80387_constant_p (RTX); \
! return code == 1 ? 1 : \
! code == 2 ? 2 : \
! 3; \
}
/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
Index: recog.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/recog.c,v
retrieving revision 1.105
diff -r1.105 recog.c
59a60
> static rtx split_insn PARAMS ((rtx));
2702a2704,2763
> /* Split single instruction. Helper function for split_all_insns.
> Return last insn in the sequence if succesfull, or NULL if unsuccesfull. */
> static rtx
> split_insn (insn)
> rtx insn;
> {
> rtx set;
> 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. */
>
> else if ((set = single_set (insn)) != NULL && 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. */
> if (reload_completed)
> {
> PUT_CODE (insn, NOTE);
> NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
> NOTE_SOURCE_FILE (insn) = 0;
> }
> }
> 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)
> {
> /* try_split returns the NOTE that INSN became. */
> PUT_CODE (insn, NOTE);
> NOTE_SOURCE_FILE (insn) = 0;
> NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
>
> /* ??? 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;
> }
2712a2774,2789
> if (!upd_life)
> {
> rtx next, insn;
>
> for (insn = get_insns (); insn ; insn = next)
> {
> rtx last;
>
> /* Can't use `next_real_insn' because that might go across
> CODE_LABELS and short-out basic blocks. */
> next = NEXT_INSN (insn);
> last = split_insn (insn);
> }
> return;
> }
>
2724c2801
< rtx set;
---
> rtx last;
2729,2751c2806,2807
< 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. */
<
< else if ((set = single_set (insn)) != NULL
< && 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. */
< if (reload_completed)
< {
< PUT_CODE (insn, NOTE);
< NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
< NOTE_SOURCE_FILE (insn) = 0;
< }
< }
< else
---
> last = split_insn (insn);
> if (last)
2753,2788c2809,2813
< /* 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)
< {
< SET_BIT (blocks, i);
< changed = 1;
<
< /* try_split returns the NOTE that INSN became. */
< PUT_CODE (insn, NOTE);
< NOTE_SOURCE_FILE (insn) = 0;
< NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
<
< /* ??? 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);
< }
< }
<
< if (insn == bb->end)
< {
< bb->end = last;
< break;
< }
< }
---
> SET_BIT (blocks, i);
> changed = 1;
> if (insn == bb->end)
> bb->end = last;
> insn = last;
2795,2799c2820
< /* ??? When we're called from just after reload, the CFG is in bad
< shape, and we may have fallen off the end. This could be fixed
< by having reload not try to delete unreachable code. Otherwise
< assert we found the end insn. */
< if (insn == NULL && upd_life)
---
> if (insn == NULL)