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++)

Reply via email to