This is a very old bug in the alias.c machinery, which is exposed during
the sched2 pass. We have in .split4:
(insn 23 22 24 4 (set (mem/f:DI (reg/v/f:DI 4 si [orig:90 p2 ] [90]) [3
*p2_9(D)+0 S8 A64])
(symbol_ref:DI ("d") <var_decl 0x7ffff6e42720 d>)) pr58831-1.c:12 85
{*movdi_internal}
(expr_list:REG_DEAD (reg/v/f:DI 4 si [orig:90 p2 ] [90])
(nil)))
[...]
(insn 61 27 62 6 (clobber (reg:DI 4 si)) -1
(nil))
(insn/f 62 61 56 6 (parallel [
(set (mem:DI (pre_dec:DI (reg/f:DI 7 sp)) [0 S8 A8])
(reg:DI 4 si))
(clobber (mem:BLK (scratch) [0 A8]))
]) pr58831-1.c:8 73 {*pushdi2_prologue}
(expr_list:REG_CFA_ADJUST_CFA (set (reg/f:DI 7 sp)
(plus:DI (reg/f:DI 7 sp)
(const_int -8 [0xfffffffffffffff8])))
(nil)))
[...]
(insn 30 29 31 6 (set (reg:DI 4 si)
(symbol_ref/f:DI ("*.LC0") [flags 0x2] <var_decl 0x7ffff6e72098
*.LC0>)) pr58831-1.c:14 85 {*movdi_internal}
(nil))
si is the 2nd argument register on x86-64 so it's live on entry. The problem
is that the clobber at insn 61 wipes out the value recorded for si:
/* A CLOBBER wipes out any old value but does not prevent a previously
unset register from acquiring a base address (i.e. reg_seen is not
set). */
if (GET_CODE (set) == CLOBBER)
{
new_reg_base_value[regno] = 0;
return;
}
by init_alias_target:
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
/* Check whether this register can hold an incoming pointer
argument. FUNCTION_ARG_REGNO_P tests outgoing register
numbers, so translate if necessary due to register windows. */
if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
&& HARD_REGNO_MODE_OK (i, Pmode))
static_reg_base_value[i] = arg_base_value;
and later copied by init_alias_analysis:
/* Mark all hard registers which may contain an address.
The stack, frame and argument pointers may contain an address.
An argument register which can hold a Pmode value may contain
an address even if it is not in BASE_REGS.
The address expression is VOIDmode for an argument and
Pmode for other registers. */
memcpy (new_reg_base_value, static_reg_base_value,
FIRST_PSEUDO_REGISTER * sizeof (rtx));
and that nothing indicates that there was a valid value before the clobber, so
the machinery wrongly records the set at insn 30. I think the fix is just to
set reg_seen[N] if static_reg_base_value[N] is non-null in the copy above made
by init_alias_analysis. Tested on x86_64-suse-linux.
Jeff, it's old code of yours, are you OK with this?
2013-10-24 Eric Botcazou <ebotca...@adacore.com>
PR rtl-optimization/58831
* alias.c (init_alias_analysis): At the beginning of each iteration, set
the reg_seen[N] bit if static_reg_base_value[N] is non-null.
2013-10-24 Eric Botcazou <ebotca...@adacore.com>
* gcc.c-torture/execute/pr58831.c: New test.
--
Eric Botcazou
#include <assert.h>
int a, *b, c, d, f, **i, p, q, *r;
short o, j;
static int __attribute__((noinline, noclone))
fn1 (int *p1, int **p2)
{
int **e = &b;
for (; p; p++)
*p1 = 1;
*e = *p2 = &d;
assert (r);
return c;
}
static int ** __attribute__((noinline, noclone))
fn2 (void)
{
for (f = 0; f != 42; f++)
{
int *g[3] = {0, 0, 0};
for (o = 0; o; o--)
for (; a > 1;)
{
int **h[1] = { &g[2] };
}
}
return &r;
}
int
main (void)
{
i = fn2 ();
fn1 (b, i);
return 0;
}
Index: alias.c
===================================================================
--- alias.c (revision 203876)
+++ alias.c (working copy)
@@ -2975,16 +2975,13 @@ init_alias_analysis (void)
/* Wipe the reg_seen array clean. */
bitmap_clear (reg_seen);
- /* Mark all hard registers which may contain an address.
- The stack, frame and argument pointers may contain an address.
- An argument register which can hold a Pmode value may contain
- an address even if it is not in BASE_REGS.
-
- The address expression is VOIDmode for an argument and
- Pmode for other registers. */
-
- memcpy (new_reg_base_value, static_reg_base_value,
- FIRST_PSEUDO_REGISTER * sizeof (rtx));
+ /* Initialize the alias information for this pass. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (static_reg_base_value[i])
+ {
+ new_reg_base_value[i] = static_reg_base_value[i];
+ bitmap_set_bit (reg_seen, i);
+ }
/* Walk the insns adding values to the new_reg_base_value array. */
for (i = 0; i < rpo_cnt; i++)