This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Re: conditional exec verify_live problem after scheduling
- To: Bernd Schmidt <bernds at redhat dot com>, rth at redhat dot com
- Subject: Re: conditional exec verify_live problem after scheduling
- From: Richard Earnshaw <rearnsha at arm dot com>
- Date: Wed, 07 Feb 2001 15:24:28 +0000
- cc: Richard Earnshaw <rearnsha at arm dot com>, gcc-bugs at gcc dot gnu dot org
- Organization: ARM Ltd.
- Reply-To: Richard dot Earnshaw at arm dot com
>
> rearnsha@arm.com said:
> > I've come across the following problem which I think is probably
> > related to your recent conditional-execution scheduling changes
> > (though it may be just uncovering an underlying problem from before).
> > The problem is in newlib/libm/common/s_modf.c when compiling arm-elf
> > and -mhard-float.
>
>
> I've finally had chance to look into this. It isn't the cond_exec
> scheduling changes per-say, but revealing a latent bug in mark_set_1. The
> problem is that the variable not_dead is calculated as the OR of the
> result of all the calls to mark_regno_cond_dead for each real reg of a
> multi-reg value. Why does this make a difference? Well, before
> scheduling we have
>
> (insn 96 94 104 (cond_exec (eq (reg:CC_NOOV 24 cc)
> (const_int 0 [0x0]))
> (set (reg:DF 3 r3 [54])
> (reg/v:DF 16 f0 [32]))) 604 {ffssi2+104} (nil)
> (nil))
> ...
> (insn 136 142 138 (cond_exec (ne (reg:CC_NOOV 24 cc)
> (const_int 0 [0x0]))
> (set (reg:SI 4 r4 [58])
> (and:SI (not:SI (reg/v:SI 3 r3 [37]))
> (reg/v:SI 12 ip [34])))) 544 {ffssi2+44} (nil)
> (expr_list:REG_DEAD (reg/v:SI 3 r3 [37])
> (expr_list:REG_DEAD (reg/v:SI 12 ip [34])
> (nil))))
>
> and since at the point of processing insn 96 the hard reg r3 is not dead,
> not_dead is set to 1 even though hard reg r4 (the upper half of (reg:DI
> r3)) is really dead at this point. This means that we erroneously leave
> r4 live at the start of the block. After scheduling the order of these
> two insns is reversed, so the liveness of r4 is calculated from a single
> call to mark_regno_cond_dead which this time tells us that the register is
> dead. Hence we get different liveness information at the start of the
> block.
I believe the following patch should fix this problem. By treating
not_dead as a bitmask of the registers that don't die we can correctly
handle partial deaths of registers that live in multi hard regs.
Bootstrapped on arm-netbsd and confirmed that it can now build the newlib
cases that previously failed.
<date> Richard Earnshaw (rearnsha@arm.com)
* flow.c (mark_set_1): Make not_dead unsigned long. For
non-pseudos, use it as a bitmask of the hard regs that
don't die.
Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.374
diff -p -r1.374 flow.c
*** flow.c 2001/02/04 22:43:59 1.374
--- flow.c 2001/02/07 15:16:45
*************** mark_set_1 (pbi, code, reg, cond, insn,
*** 4655,4661 ****
int flags;
{
int regno_first = -1, regno_last = -1;
! int not_dead = 0;
int i;
/* Modifying just one hardware register of a multi-reg value or just a
--- 4655,4661 ----
int flags;
{
int regno_first = -1, regno_last = -1;
! unsigned long not_dead = 0;
int i;
/* Modifying just one hardware register of a multi-reg value or just a
*************** mark_set_1 (pbi, code, reg, cond, insn,
*** 4830,4836 ****
{
for (i = regno_first; i <= regno_last; ++i)
if (! mark_regno_cond_dead (pbi, i, cond))
! not_dead = 1;
}
#endif
--- 4830,4836 ----
{
for (i = regno_first; i <= regno_last; ++i)
if (! mark_regno_cond_dead (pbi, i, cond))
! not_dead |= 1 << (i - regno_first);
}
#endif
*************** mark_set_1 (pbi, code, reg, cond, insn,
*** 4943,4949 ****
/* Mark the register as being dead. */
if (some_was_live
- && ! not_dead
/* The stack pointer is never dead. Well, not strictly true,
but it's very difficult to tell from here. Hopefully
combine_stack_adjustments will fix up the most egregious
--- 4943,4948 ----
*************** mark_set_1 (pbi, code, reg, cond, insn,
*** 4951,4957 ****
&& regno_first != STACK_POINTER_REGNUM)
{
for (i = regno_first; i <= regno_last; ++i)
! CLEAR_REGNO_REG_SET (pbi->reg_live, i);
}
}
else if (GET_CODE (reg) == REG)
--- 4950,4957 ----
&& regno_first != STACK_POINTER_REGNUM)
{
for (i = regno_first; i <= regno_last; ++i)
! if (!(not_dead & (1 << (i - regno_first))))
! CLEAR_REGNO_REG_SET (pbi->reg_live, i);
}
}
else if (GET_CODE (reg) == REG)