diff mbox

Fix PR rtl-optimization/58831

Message ID 3219649.lQJTE2xl1Q@polaris
State New
Headers show

Commit Message

Eric Botcazou Oct. 24, 2013, 9:28 p.m. UTC
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  <ebotcazou@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  <ebotcazou@adacore.com>

	* gcc.c-torture/execute/pr58831.c: New test.

Comments

Jeff Law Oct. 25, 2013, 4:59 a.m. UTC | #1
On 10/24/13 15:28, Eric Botcazou wrote:
> 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?
Actually I think it's jfc's code; he had a major revamp of alias.c back 
in the early egcs days and getting it integrated was one of the 
project's early wins.  Sadly, jfc hasn't been involved in GCC work for a 
long long time.

Anyway, I think the issue here is that once we set 
new_reg_base_value[regno] to zero, when we do encounter insn 30, we 
assume that's the first set of (reg 4) and we use the RHS as a base value.

The result is we end up with something in new_reg_base_value[4] that is 
not correct for the entire life.  ie, from function entry to the clobber 
(reg 4) has a value totally unrelated to what we've stored in 
new_reg_base_value[4]?  RIght?



My memory of all this is fuzzy, but this code in alias.c is effectively 
trying to compute a set of flow independent base values for each 
register.  If we have two unrelated values going into a register, then 
we need to essentially say we know nothing about its address and the 
aliases that creates.






>
>
> 2013-10-24  Eric Botcazou  <ebotcazou@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  <ebotcazou@adacore.com>
>
> 	* gcc.c-torture/execute/pr58831.c: New test.
Seems reasonable to me, assuming my understandings noted above are correct.



jeff
Eric Botcazou Oct. 25, 2013, 8:32 a.m. UTC | #2
> Actually I think it's jfc's code; he had a major revamp of alias.c back
> in the early egcs days and getting it integrated was one of the
> project's early wins.  Sadly, jfc hasn't been involved in GCC work for a
> long long time.

OK, thanks for the clarification.

> Anyway, I think the issue here is that once we set
> new_reg_base_value[regno] to zero, when we do encounter insn 30, we
> assume that's the first set of (reg 4) and we use the RHS as a base value.
> 
> The result is we end up with something in new_reg_base_value[4] that is
> not correct for the entire life.  ie, from function entry to the clobber
> (reg 4) has a value totally unrelated to what we've stored in
> new_reg_base_value[4]?  RIght?

Yes, that's exactly it.

> Seems reasonable to me, assuming my understandings noted above are correct.

Thanks.
diff mbox

Patch

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