This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Avoid most of calls to side_effects_p
- From: Jan Hubicka <jh at suse dot cz>
- To: Ulrich Weigand <Ulrich dot Weigand at de dot ibm dot com>
- Cc: jh at suse dot cz, rth at redhat dot com, gcc-patches at gcc dot gnu dot org
- Date: Thu, 17 Apr 2003 15:05:22 +0200
- Subject: Re: Avoid most of calls to side_effects_p
- References: <OFA4B91C34.F1776B3F-ONC1256D09.006A12B5@de.ibm.com>
> Jan Hubicka wrote:
>
> >*************** count_reg_usage (x, counts, dest, incr)
> >*** 7494,7508 ****
> > /* Unless we are setting a REG, count everything in SET_DEST. */
> > if (GET_CODE (SET_DEST (x)) != REG)
> > count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
> >-
> >- /* If SRC has side-effects, then we can't delete this insn, so the
> >- usage of SET_DEST inside SRC counts.
> >-
> >- ??? Strictly-speaking, we might be preserving this insn
> >- because some other SET has side-effects, but that's hard
> >- to do and can't happen now. */
> > count_reg_usage (SET_SRC (x), counts,
> >! side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST
> (x),
> > incr);
> > return;
> >
> >--- 7494,7501 ----
> > /* Unless we are setting a REG, count everything in SET_DEST. */
> > if (GET_CODE (SET_DEST (x)) != REG)
> > count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
> > count_reg_usage (SET_SRC (x), counts,
> >! SET_DEST (x),
> > incr);
> > return;
>
> This causes miscompiles of the Linux kernel on s390.
>
> The problem is code like this:
>
> unsigned long __xchg(unsigned char * ptr)
> {
> asm volatile ("ptr in %0"
> : "+a" (ptr) : : "0", "1", "2" );
> }
>
> which generates:
>
> (insn 3 2 4 (nil) (set (reg/v/f:DI 41)
> (reg:DI 2 %r2)) -1 (nil)
> (nil))
>
> (insn 9 7 10 (nil) (parallel [
> (set (reg/v/f:DI 41)
> (asm_operands/v:DI ("ptr in %0") ("=a") 0 [
> (reg/v/f:DI 41)
> ]
> [
> (asm_input:DI ("0"))
> ] ("qdio.i") 4))
> (clobber (reg:QI 2 %r2))
> (clobber (reg:QI 1 %r1))
> (clobber (reg:QI 0 %r0))
> ]) -1 (nil)
> (nil))
>
>
> Now, delete_trivially_dead_insns deletes insn 3, because
> count_reg_usage reports 0 usage of reg 41. But of course,
> as insn 9 is a volatile asm, it is not deleted, and the
> use of reg 41 becomes uninitialized ...
Sorry for the delay. I hope this patch will solve your problem.
Without re-introducing those insanely many check this appears to be only
sollution left, even when I don't like idea of passing extra argument to
the already expensive recursive function it appears to make no
measurable slowdowns.
Can you please test whether it helps your testcase?
I am currently testing it on i386.
Honza
Thu Apr 17 14:44:42 CEST 2003 Jan Hubicka <jh at suse dot cz>
* cse.c (count_reg_usage): New argument INSN; verify that the insn
can be deleted before not counting register insn uses and modifies.
Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.259
diff -c -3 -p -r1.259 cse.c
*** cse.c 10 Apr 2003 05:24:26 -0000 1.259
--- cse.c 17 Apr 2003 12:44:26 -0000
*************** static void invalidate_skipped_block PAR
*** 651,657 ****
static void cse_check_loop_start PARAMS ((rtx, rtx, void *));
static void cse_set_around_loop PARAMS ((rtx, rtx, rtx));
static rtx cse_basic_block PARAMS ((rtx, rtx, struct branch_path *, int));
! static void count_reg_usage PARAMS ((rtx, int *, rtx, int));
static int check_for_label_ref PARAMS ((rtx *, void *));
extern void dump_class PARAMS ((struct table_elt*));
static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
--- 651,657 ----
static void cse_check_loop_start PARAMS ((rtx, rtx, void *));
static void cse_set_around_loop PARAMS ((rtx, rtx, rtx));
static rtx cse_basic_block PARAMS ((rtx, rtx, struct branch_path *, int));
! static void count_reg_usage PARAMS ((rtx, int *, rtx, int, rtx));
static int check_for_label_ref PARAMS ((rtx *, void *));
extern void dump_class PARAMS ((struct table_elt*));
static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
*************** check_for_label_ref (rtl, data)
*** 7452,7462 ****
modify the liveness of DEST. */
static void
! count_reg_usage (x, counts, dest, incr)
rtx x;
int *counts;
rtx dest;
int incr;
{
enum rtx_code code;
rtx note;
--- 7452,7463 ----
modify the liveness of DEST. */
static void
! count_reg_usage (x, counts, dest, incr, insn)
rtx x;
int *counts;
rtx dest;
int incr;
+ rtx insn;
{
enum rtx_code code;
rtx note;
*************** count_reg_usage (x, counts, dest, incr)
*** 7469,7475 ****
switch (code = GET_CODE (x))
{
case REG:
! if (x != dest)
counts[REGNO (x)] += incr;
return;
--- 7470,7480 ----
switch (code = GET_CODE (x))
{
case REG:
! if (x != dest
! /* Do not delete instructions initializing operands needed by dead
! instruction with side effects. */
! || (!counts[REGNO (x)] && incr > 0
! && insn_live_p (insn, NULL)))
counts[REGNO (x)] += incr;
return;
*************** count_reg_usage (x, counts, dest, incr)
*** 7487,7518 ****
/* If we are clobbering a MEM, mark any registers inside the address
as being used. */
if (GET_CODE (XEXP (x, 0)) == MEM)
! count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
return;
case SET:
/* Unless we are setting a REG, count everything in SET_DEST. */
if (GET_CODE (SET_DEST (x)) != REG)
! count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
count_reg_usage (SET_SRC (x), counts,
SET_DEST (x),
! incr);
return;
case CALL_INSN:
! count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr);
/* Fall through. */
case INSN:
case JUMP_INSN:
! count_reg_usage (PATTERN (x), counts, NULL_RTX, incr);
/* Things used in a REG_EQUAL note aren't dead since loop may try to
use them. */
note = find_reg_equal_equiv_note (x);
if (note)
! count_reg_usage (XEXP (note, 0), counts, NULL_RTX, incr);
return;
case INSN_LIST:
--- 7492,7524 ----
/* If we are clobbering a MEM, mark any registers inside the address
as being used. */
if (GET_CODE (XEXP (x, 0)) == MEM)
! count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr, insn);
return;
case SET:
/* Unless we are setting a REG, count everything in SET_DEST. */
if (GET_CODE (SET_DEST (x)) != REG)
! count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr, insn);
count_reg_usage (SET_SRC (x), counts,
SET_DEST (x),
! incr, insn);
return;
case CALL_INSN:
! count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr,
! insn);
/* Fall through. */
case INSN:
case JUMP_INSN:
! count_reg_usage (PATTERN (x), counts, NULL_RTX, incr, insn);
/* Things used in a REG_EQUAL note aren't dead since loop may try to
use them. */
note = find_reg_equal_equiv_note (x);
if (note)
! count_reg_usage (XEXP (note, 0), counts, NULL_RTX, incr, insn);
return;
case INSN_LIST:
*************** count_reg_usage (x, counts, dest, incr)
*** 7526,7535 ****
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
! count_reg_usage (XEXP (x, i), counts, dest, incr);
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
! count_reg_usage (XVECEXP (x, i, j), counts, dest, incr);
}
}
--- 7532,7541 ----
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
! count_reg_usage (XEXP (x, i), counts, dest, incr, insn);
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
! count_reg_usage (XVECEXP (x, i, j), counts, dest, incr, insn);
}
}
*************** set_live_p (set, insn, counts)
*** 7557,7563 ****
#endif
else if (GET_CODE (SET_DEST (set)) != REG
|| REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
! || counts[REGNO (SET_DEST (set))] != 0
|| side_effects_p (SET_SRC (set))
/* An ADDRESSOF expression can turn into a use of the
internal arg pointer, so always consider the
--- 7563,7569 ----
#endif
else if (GET_CODE (SET_DEST (set)) != REG
|| REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
! || (counts && counts[REGNO (SET_DEST (set))] != 0)
|| side_effects_p (SET_SRC (set))
/* An ADDRESSOF expression can turn into a use of the
internal arg pointer, so always consider the
*************** set_live_p (set, insn, counts)
*** 7568,7574 ****
return false;
}
! /* Return true if insn is live. */
static bool
insn_live_p (insn, counts)
--- 7574,7582 ----
return false;
}
! /* Return true if insn is live.
! When COUNTS is NULL return true if insn is live because of the side effects.
! */
static bool
insn_live_p (insn, counts)
*************** dead_libcall_p (insn, counts)
*** 7623,7638 ****
new = XEXP (note, 0);
/* While changing insn, we must update the counts accordingly. */
! count_reg_usage (insn, counts, NULL_RTX, -1);
if (set && validate_change (insn, &SET_SRC (set), new, 0))
{
! count_reg_usage (insn, counts, NULL_RTX, 1);
remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
remove_note (insn, note);
return true;
}
! count_reg_usage (insn, counts, NULL_RTX, 1);
}
return false;
}
--- 7631,7646 ----
new = XEXP (note, 0);
/* While changing insn, we must update the counts accordingly. */
! count_reg_usage (insn, counts, NULL_RTX, -1, insn);
if (set && validate_change (insn, &SET_SRC (set), new, 0))
{
! count_reg_usage (insn, counts, NULL_RTX, 1, insn);
remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
remove_note (insn, note);
return true;
}
! count_reg_usage (insn, counts, NULL_RTX, 1, insn);
}
return false;
}
*************** delete_trivially_dead_insns (insns, nreg
*** 7659,7665 ****
/* First count the number of times each register is used. */
counts = (int *) xcalloc (nreg, sizeof (int));
for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
! count_reg_usage (insn, counts, NULL_RTX, 1);
do
{
--- 7667,7673 ----
/* First count the number of times each register is used. */
counts = (int *) xcalloc (nreg, sizeof (int));
for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
! count_reg_usage (insn, counts, NULL_RTX, 1, insn);
do
{
*************** delete_trivially_dead_insns (insns, nreg
*** 7703,7709 ****
if (! live_insn)
{
! count_reg_usage (insn, counts, NULL_RTX, -1);
delete_insn_and_edges (insn);
ndead++;
}
--- 7711,7717 ----
if (! live_insn)
{
! count_reg_usage (insn, counts, NULL_RTX, -1, insn);
delete_insn_and_edges (insn);
ndead++;