diff mbox

Ping: Re: [patch middle-end]: Fix PR/48814 - [4.4/4.5/4.6/4.7 Regression] Incorrect scalar increment result

Message ID CAEwic4YWJriFkeTfyxn-SO4mxunbNkUzod2+UrRHAoHoU65LSg@mail.gmail.com
State New
Headers show

Commit Message

Kai Tietz Feb. 8, 2012, 9:25 p.m. UTC
2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>
> count despite being declared volatile and only loaded once in the source
> is loaded twice in gimple.  If it were a HW register which destroys the
> device after the 2nd load without an intervening store you'd wrecked
> the device ;)
>
> Richard.

Thanks for explaination.  I tried to flip order for lhs/rhs in
gimplify_modify_expr & co.  Issue here is that for some cases we are
relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
like:

typedef const unsigned char _Jv_Utf8Const;
typedef __SIZE_TYPE__ uaddr;

void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
{
  union {
    _Jv_Utf8Const *signature;
    uaddr signature_bits;
  };
  signature = s;
  special = signature_bits & 1;
  signature_bits -= special;
  s = signature;
}

So I modified gimplify_self_mod_expr for post-inc/dec so that we use
following sequence
and add it to pre_p for it:

tmp = lhs;
lvalue = tmp (+/-) rhs
*expr_p = tmp;

ChangeLog

2012-02-08  Kai Tietz  <ktietz@redhat.com>

	PR middle-end/48814
	* gimplify.c (gimplify_self_mod_expr): Move for
	postfix-inc/dec the modification in pre and return
	temporary with origin value.

2012-02-08  Kai Tietz  <ktietz@redhat.com>

	* gcc.c-torture/execute/pr48814-1.c: New test.
	* gcc.c-torture/execute/pr48814-2.c: New test.
	* gcc.dg/tree-ssa/assign-1.c: New test.
	* gcc.dg/tree-ssa/assign-2.c: New test.

I did boostrap for all languages (including Ada and Obj-C++) and
regression tests on host x86_64-unknown-linux-gnu.  Ok for apply?

Regards,
Kai

Comments

Richard Biener Feb. 9, 2012, 10:29 a.m. UTC | #1
On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>
>> count despite being declared volatile and only loaded once in the source
>> is loaded twice in gimple.  If it were a HW register which destroys the
>> device after the 2nd load without an intervening store you'd wrecked
>> the device ;)
>>
>> Richard.
>
> Thanks for explaination.  I tried to flip order for lhs/rhs in
> gimplify_modify_expr & co.  Issue here is that for some cases we are
> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
> like:
>
> typedef const unsigned char _Jv_Utf8Const;
> typedef __SIZE_TYPE__ uaddr;
>
> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
> {
>  union {
>    _Jv_Utf8Const *signature;
>    uaddr signature_bits;
>  };
>  signature = s;
>  special = signature_bits & 1;
>  signature_bits -= special;
>  s = signature;
> }
>
> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
> following sequence
> and add it to pre_p for it:
>
> tmp = lhs;
> lvalue = tmp (+/-) rhs
> *expr_p = tmp;

As I explained this is the wrong place to fix the PR.  The issue is not
about self-modifying expressions but about evaluating call argument
side-effects before side-effects of the lhs.

Richard.

> ChangeLog
>
> 2012-02-08  Kai Tietz  <ktietz@redhat.com>
>
>        PR middle-end/48814
>        * gimplify.c (gimplify_self_mod_expr): Move for
>        postfix-inc/dec the modification in pre and return
>        temporary with origin value.
>
> 2012-02-08  Kai Tietz  <ktietz@redhat.com>
>
>        * gcc.c-torture/execute/pr48814-1.c: New test.
>        * gcc.c-torture/execute/pr48814-2.c: New test.
>        * gcc.dg/tree-ssa/assign-1.c: New test.
>        * gcc.dg/tree-ssa/assign-2.c: New test.
>
> I did boostrap for all languages (including Ada and Obj-C++) and
> regression tests on host x86_64-unknown-linux-gnu.  Ok for apply?
>
> Regards,
> Kai
>
> Index: gcc/gcc/gimplify.c
> ===================================================================
> --- gcc.orig/gcc/gimplify.c
> +++ gcc/gcc/gimplify.c
> @@ -2197,7 +2197,7 @@ gimplify_self_mod_expr (tree *expr_p, gi
>                        bool want_value)
>  {
>   enum tree_code code;
> -  tree lhs, lvalue, rhs, t1;
> +  tree lhs, lvalue, rhs, t1, t2;
>   gimple_seq post = NULL, *orig_post_p = post_p;
>   bool postfix;
>   enum tree_code arith_code;
> @@ -2264,20 +2264,23 @@ gimplify_self_mod_expr (tree *expr_p, gi
>       arith_code = POINTER_PLUS_EXPR;
>     }
>
> -  t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
> -
> -  if (postfix)
> -    {
> -      gimplify_assign (lvalue, t1, orig_post_p);
> -      gimplify_seq_add_seq (orig_post_p, post);
> -      *expr_p = lhs;
> -      return GS_ALL_DONE;
> -    }
> -  else
> +  if (!postfix)
>     {
> +      t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
>       *expr_p = build2 (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
>       return GS_OK;
>     }
> +
> +  /* Assign lhs to temporary variable.  */
> +  t2 = create_tmp_var (TREE_TYPE (lhs), NULL);
> +  gimplify_assign (t2, lhs, pre_p);
> +  /* Do increment and assign it to lvalue.  */
> +  t1 = build2 (arith_code, TREE_TYPE (*expr_p), t2, rhs);
> +  gimplify_assign (lvalue, t1, pre_p);
> +
> +  gimplify_seq_add_seq (orig_post_p, post);
> +  *expr_p = t2;
> +  return GS_ALL_DONE;
>  }
>
>  /* If *EXPR_P has a variable sized type, wrap it in a WITH_SIZE_EXPR.  */
> Index: gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-1.c
> ===================================================================
> --- /dev/null
> +++ gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-1.c
> @@ -0,0 +1,18 @@
> +extern void abort (void);
> +
> +int arr[] = {1,2,3,4};
> +int count = 0;
> +
> +int __attribute__((noinline))
> +incr (void)
> +{
> +  return ++count;
> +}
> +
> +int main()
> +{
> +  arr[count++] = incr ();
> +  if (count != 2 || arr[count] != 3)
> +    abort ();
> +  return 0;
> +}
> Index: gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-2.c
> ===================================================================
> --- /dev/null
> +++ gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-2.c
> @@ -0,0 +1,18 @@
> +extern void abort (void);
> +
> +int arr[] = {1,2,3,4};
> +int count = 0;
> +
> +int
> +incr (void)
> +{
> +  return ++count;
> +}
> +
> +int main()
> +{
> +  arr[count++] = incr ();
> +  if (count != 2 || arr[count] != 3)
> +    abort ();
> +  return 0;
> +}
> Index: gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-1.c
> ===================================================================
> --- /dev/null
> +++ gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-1.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +volatile int count;
> +void bar(int);
> +void foo()
> +{
> + bar(count++);
> +}
> +
> +/* { dg-final { scan-tree-dump-times "count =" 1 "optimized"} } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
> Index: gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-2.c
> ===================================================================
> --- /dev/null
> +++ gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-2.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +volatile int count;
> +int arr[4];
> +void foo()
> +{
> + arr[count++] = 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "count =" 1 "optimized"} } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
> +
Richard Biener Feb. 9, 2012, 10:53 a.m. UTC | #2
On Thu, Feb 9, 2012 at 11:29 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>>
>>> count despite being declared volatile and only loaded once in the source
>>> is loaded twice in gimple.  If it were a HW register which destroys the
>>> device after the 2nd load without an intervening store you'd wrecked
>>> the device ;)
>>>
>>> Richard.
>>
>> Thanks for explaination.  I tried to flip order for lhs/rhs in
>> gimplify_modify_expr & co.  Issue here is that for some cases we are
>> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
>> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
>> like:
>>
>> typedef const unsigned char _Jv_Utf8Const;
>> typedef __SIZE_TYPE__ uaddr;
>>
>> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
>> {
>>  union {
>>    _Jv_Utf8Const *signature;
>>    uaddr signature_bits;
>>  };
>>  signature = s;
>>  special = signature_bits & 1;
>>  signature_bits -= special;
>>  s = signature;
>> }
>>
>> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
>> following sequence
>> and add it to pre_p for it:
>>
>> tmp = lhs;
>> lvalue = tmp (+/-) rhs
>> *expr_p = tmp;
>
> As I explained this is the wrong place to fix the PR.  The issue is not
> about self-modifying expressions but about evaluating call argument
> side-effects before side-effects of the lhs.

I am testing the attached instead.

Richard.

2012-02-09  Richard Guenther  <rguenther@suse.de>

        PR middle-end/48814
        * gimplify.c (gimplify_modify_expr): Perform side-effects of
        the RHS before those of the LHS.

2012-02-08  Kai Tietz  <ktietz@redhat.com>

        * gcc.c-torture/execute/pr48814-1.c: New test.
        * gcc.c-torture/execute/pr48814-2.c: New test.
        * gcc.dg/tree-ssa/assign-1.c: New test.
        * gcc.dg/tree-ssa/assign-2.c: New test.
Richard Biener Feb. 9, 2012, 12:56 p.m. UTC | #3
On Thu, Feb 9, 2012 at 11:53 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Thu, Feb 9, 2012 at 11:29 AM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>>>
>>>> count despite being declared volatile and only loaded once in the source
>>>> is loaded twice in gimple.  If it were a HW register which destroys the
>>>> device after the 2nd load without an intervening store you'd wrecked
>>>> the device ;)
>>>>
>>>> Richard.
>>>
>>> Thanks for explaination.  I tried to flip order for lhs/rhs in
>>> gimplify_modify_expr & co.  Issue here is that for some cases we are
>>> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
>>> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
>>> like:
>>>
>>> typedef const unsigned char _Jv_Utf8Const;
>>> typedef __SIZE_TYPE__ uaddr;
>>>
>>> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
>>> {
>>>  union {
>>>    _Jv_Utf8Const *signature;
>>>    uaddr signature_bits;
>>>  };
>>>  signature = s;
>>>  special = signature_bits & 1;
>>>  signature_bits -= special;
>>>  s = signature;
>>> }
>>>
>>> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
>>> following sequence
>>> and add it to pre_p for it:
>>>
>>> tmp = lhs;
>>> lvalue = tmp (+/-) rhs
>>> *expr_p = tmp;
>>
>> As I explained this is the wrong place to fix the PR.  The issue is not
>> about self-modifying expressions but about evaluating call argument
>> side-effects before side-effects of the lhs.
>
> I am testing the attached instead.

Doesn't work.  Btw, Kai, your patch surely breaks things if you put
the lvalue update into the pre queue.

Consider a simple

 a[i++] = i;

you gimplify that to

  i.0 = i;
  D.1709 = i.0;
  i = D.1709 + 1;
  a[D.1709] = i;

which is wrong.

Seems we are lacking some basic pre-/post-modify testcases ...

Richard.
Kai Tietz Feb. 9, 2012, 1:48 p.m. UTC | #4
2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
> On Thu, Feb 9, 2012 at 11:53 AM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> On Thu, Feb 9, 2012 at 11:29 AM, Richard Guenther
>> <richard.guenther@gmail.com> wrote:
>>> On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>>> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>>>>
>>>>> count despite being declared volatile and only loaded once in the source
>>>>> is loaded twice in gimple.  If it were a HW register which destroys the
>>>>> device after the 2nd load without an intervening store you'd wrecked
>>>>> the device ;)
>>>>>
>>>>> Richard.
>>>>
>>>> Thanks for explaination.  I tried to flip order for lhs/rhs in
>>>> gimplify_modify_expr & co.  Issue here is that for some cases we are
>>>> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
>>>> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
>>>> like:
>>>>
>>>> typedef const unsigned char _Jv_Utf8Const;
>>>> typedef __SIZE_TYPE__ uaddr;
>>>>
>>>> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
>>>> {
>>>>  union {
>>>>    _Jv_Utf8Const *signature;
>>>>    uaddr signature_bits;
>>>>  };
>>>>  signature = s;
>>>>  special = signature_bits & 1;
>>>>  signature_bits -= special;
>>>>  s = signature;
>>>> }
>>>>
>>>> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
>>>> following sequence
>>>> and add it to pre_p for it:
>>>>
>>>> tmp = lhs;
>>>> lvalue = tmp (+/-) rhs
>>>> *expr_p = tmp;
>>>
>>> As I explained this is the wrong place to fix the PR.  The issue is not
>>> about self-modifying expressions but about evaluating call argument
>>> side-effects before side-effects of the lhs.
>>
>> I am testing the attached instead.
>
> Doesn't work.  Btw, Kai, your patch surely breaks things if you put
> the lvalue update into the pre queue.
>
> Consider a simple
>
>  a[i++] = i;
>
> you gimplify that to
>
>  i.0 = i;
>  D.1709 = i.0;
>  i = D.1709 + 1;
>  a[D.1709] = i;
>
> which is wrong.
>
> Seems we are lacking some basic pre-/post-modify testcases ...
>
> Richard.

Why, this should be wrong?  In fact C specification just says that the
post-inc has to happen at least before next sequence-point.  It
doesn't say that the increment has to happen after evaluation of rhs.

The produced gimple for the following C-code

int arr[128];

void foo (int i)
{
  arr[i++] = i;
}

is:

foo (int i)
{
  int D.1364;

  D.1364 = i;
  i = D.1364 + 1;
  arr[D.1364] = i;
}

which looks to me from description of the C-specification correct.

Kai
Richard Biener Feb. 9, 2012, 2:41 p.m. UTC | #5
On Thu, Feb 9, 2012 at 2:48 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> 2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
>> On Thu, Feb 9, 2012 at 11:53 AM, Richard Guenther
>> <richard.guenther@gmail.com> wrote:
>>> On Thu, Feb 9, 2012 at 11:29 AM, Richard Guenther
>>> <richard.guenther@gmail.com> wrote:
>>>> On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>>>> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>>>>>
>>>>>> count despite being declared volatile and only loaded once in the source
>>>>>> is loaded twice in gimple.  If it were a HW register which destroys the
>>>>>> device after the 2nd load without an intervening store you'd wrecked
>>>>>> the device ;)
>>>>>>
>>>>>> Richard.
>>>>>
>>>>> Thanks for explaination.  I tried to flip order for lhs/rhs in
>>>>> gimplify_modify_expr & co.  Issue here is that for some cases we are
>>>>> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
>>>>> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
>>>>> like:
>>>>>
>>>>> typedef const unsigned char _Jv_Utf8Const;
>>>>> typedef __SIZE_TYPE__ uaddr;
>>>>>
>>>>> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
>>>>> {
>>>>>  union {
>>>>>    _Jv_Utf8Const *signature;
>>>>>    uaddr signature_bits;
>>>>>  };
>>>>>  signature = s;
>>>>>  special = signature_bits & 1;
>>>>>  signature_bits -= special;
>>>>>  s = signature;
>>>>> }
>>>>>
>>>>> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
>>>>> following sequence
>>>>> and add it to pre_p for it:
>>>>>
>>>>> tmp = lhs;
>>>>> lvalue = tmp (+/-) rhs
>>>>> *expr_p = tmp;
>>>>
>>>> As I explained this is the wrong place to fix the PR.  The issue is not
>>>> about self-modifying expressions but about evaluating call argument
>>>> side-effects before side-effects of the lhs.
>>>
>>> I am testing the attached instead.
>>
>> Doesn't work.  Btw, Kai, your patch surely breaks things if you put
>> the lvalue update into the pre queue.
>>
>> Consider a simple
>>
>>  a[i++] = i;
>>
>> you gimplify that to
>>
>>  i.0 = i;
>>  D.1709 = i.0;
>>  i = D.1709 + 1;
>>  a[D.1709] = i;
>>
>> which is wrong.
>>
>> Seems we are lacking some basic pre-/post-modify testcases ...
>>
>> Richard.
>
> Why, this should be wrong?  In fact C specification just says that the
> post-inc has to happen at least before next sequence-point.  It
> doesn't say that the increment has to happen after evaluation of rhs.
>
> The produced gimple for the following C-code
>
> int arr[128];
>
> void foo (int i)
> {
>  arr[i++] = i;
> }
>
> is:
>
> foo (int i)
> {
>  int D.1364;
>
>  D.1364 = i;
>  i = D.1364 + 1;
>  arr[D.1364] = i;
> }
>
> which looks to me from description of the C-specification correct.

Hm, indeed.  I'll test the following shorter patch and add the struct-return
volatile testcase.

Richard.
Richard Biener Feb. 9, 2012, 4:18 p.m. UTC | #6
On Thu, Feb 9, 2012 at 3:41 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Thu, Feb 9, 2012 at 2:48 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>> 2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
>>> On Thu, Feb 9, 2012 at 11:53 AM, Richard Guenther
>>> <richard.guenther@gmail.com> wrote:
>>>> On Thu, Feb 9, 2012 at 11:29 AM, Richard Guenther
>>>> <richard.guenther@gmail.com> wrote:
>>>>> On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>>>>> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>>>>>>
>>>>>>> count despite being declared volatile and only loaded once in the source
>>>>>>> is loaded twice in gimple.  If it were a HW register which destroys the
>>>>>>> device after the 2nd load without an intervening store you'd wrecked
>>>>>>> the device ;)
>>>>>>>
>>>>>>> Richard.
>>>>>>
>>>>>> Thanks for explaination.  I tried to flip order for lhs/rhs in
>>>>>> gimplify_modify_expr & co.  Issue here is that for some cases we are
>>>>>> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
>>>>>> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
>>>>>> like:
>>>>>>
>>>>>> typedef const unsigned char _Jv_Utf8Const;
>>>>>> typedef __SIZE_TYPE__ uaddr;
>>>>>>
>>>>>> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
>>>>>> {
>>>>>>  union {
>>>>>>    _Jv_Utf8Const *signature;
>>>>>>    uaddr signature_bits;
>>>>>>  };
>>>>>>  signature = s;
>>>>>>  special = signature_bits & 1;
>>>>>>  signature_bits -= special;
>>>>>>  s = signature;
>>>>>> }
>>>>>>
>>>>>> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
>>>>>> following sequence
>>>>>> and add it to pre_p for it:
>>>>>>
>>>>>> tmp = lhs;
>>>>>> lvalue = tmp (+/-) rhs
>>>>>> *expr_p = tmp;
>>>>>
>>>>> As I explained this is the wrong place to fix the PR.  The issue is not
>>>>> about self-modifying expressions but about evaluating call argument
>>>>> side-effects before side-effects of the lhs.
>>>>
>>>> I am testing the attached instead.
>>>
>>> Doesn't work.  Btw, Kai, your patch surely breaks things if you put
>>> the lvalue update into the pre queue.
>>>
>>> Consider a simple
>>>
>>>  a[i++] = i;
>>>
>>> you gimplify that to
>>>
>>>  i.0 = i;
>>>  D.1709 = i.0;
>>>  i = D.1709 + 1;
>>>  a[D.1709] = i;
>>>
>>> which is wrong.
>>>
>>> Seems we are lacking some basic pre-/post-modify testcases ...
>>>
>>> Richard.
>>
>> Why, this should be wrong?  In fact C specification just says that the
>> post-inc has to happen at least before next sequence-point.  It
>> doesn't say that the increment has to happen after evaluation of rhs.
>>
>> The produced gimple for the following C-code
>>
>> int arr[128];
>>
>> void foo (int i)
>> {
>>  arr[i++] = i;
>> }
>>
>> is:
>>
>> foo (int i)
>> {
>>  int D.1364;
>>
>>  D.1364 = i;
>>  i = D.1364 + 1;
>>  arr[D.1364] = i;
>> }
>>
>> which looks to me from description of the C-specification correct.
>
> Hm, indeed.  I'll test the following shorter patch and add the struct-return
> volatile testcase.

Works apart from

Running target unix/
FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test
FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test

Maybe invalid testcases.  Who knows ... same fails happen with your patch.

Richard.

> Richard.
Kai Tietz Feb. 10, 2012, 8:36 a.m. UTC | #7
2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
> On Thu, Feb 9, 2012 at 3:41 PM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> On Thu, Feb 9, 2012 at 2:48 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>> 2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
>>>> On Thu, Feb 9, 2012 at 11:53 AM, Richard Guenther
>>>> <richard.guenther@gmail.com> wrote:
>>>>> On Thu, Feb 9, 2012 at 11:29 AM, Richard Guenther
>>>>> <richard.guenther@gmail.com> wrote:
>>>>>> On Wed, Feb 8, 2012 at 10:25 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>>>>>> 2012/1/11 Richard Guenther <richard.guenther@gmail.com>:
>>>>>>>>
>>>>>>>> count despite being declared volatile and only loaded once in the source
>>>>>>>> is loaded twice in gimple.  If it were a HW register which destroys the
>>>>>>>> device after the 2nd load without an intervening store you'd wrecked
>>>>>>>> the device ;)
>>>>>>>>
>>>>>>>> Richard.
>>>>>>>
>>>>>>> Thanks for explaination.  I tried to flip order for lhs/rhs in
>>>>>>> gimplify_modify_expr & co.  Issue here is that for some cases we are
>>>>>>> relying here on lhs for gimplifying rhs (is_gimple_reg_rhs_or_call vs
>>>>>>> is_gimple_mem_rhs_or_call) and this doesn't work for cases in C++
>>>>>>> like:
>>>>>>>
>>>>>>> typedef const unsigned char _Jv_Utf8Const;
>>>>>>> typedef __SIZE_TYPE__ uaddr;
>>>>>>>
>>>>>>> void maybe_adjust_signature (_Jv_Utf8Const *&s, uaddr &special)
>>>>>>> {
>>>>>>>  union {
>>>>>>>    _Jv_Utf8Const *signature;
>>>>>>>    uaddr signature_bits;
>>>>>>>  };
>>>>>>>  signature = s;
>>>>>>>  special = signature_bits & 1;
>>>>>>>  signature_bits -= special;
>>>>>>>  s = signature;
>>>>>>> }
>>>>>>>
>>>>>>> So I modified gimplify_self_mod_expr for post-inc/dec so that we use
>>>>>>> following sequence
>>>>>>> and add it to pre_p for it:
>>>>>>>
>>>>>>> tmp = lhs;
>>>>>>> lvalue = tmp (+/-) rhs
>>>>>>> *expr_p = tmp;
>>>>>>
>>>>>> As I explained this is the wrong place to fix the PR.  The issue is not
>>>>>> about self-modifying expressions but about evaluating call argument
>>>>>> side-effects before side-effects of the lhs.
>>>>>
>>>>> I am testing the attached instead.
>>>>
>>>> Doesn't work.  Btw, Kai, your patch surely breaks things if you put
>>>> the lvalue update into the pre queue.
>>>>
>>>> Consider a simple
>>>>
>>>>  a[i++] = i;
>>>>
>>>> you gimplify that to
>>>>
>>>>  i.0 = i;
>>>>  D.1709 = i.0;
>>>>  i = D.1709 + 1;
>>>>  a[D.1709] = i;
>>>>
>>>> which is wrong.
>>>>
>>>> Seems we are lacking some basic pre-/post-modify testcases ...
>>>>
>>>> Richard.
>>>
>>> Why, this should be wrong?  In fact C specification just says that the
>>> post-inc has to happen at least before next sequence-point.  It
>>> doesn't say that the increment has to happen after evaluation of rhs.
>>>
>>> The produced gimple for the following C-code
>>>
>>> int arr[128];
>>>
>>> void foo (int i)
>>> {
>>>  arr[i++] = i;
>>> }
>>>
>>> is:
>>>
>>> foo (int i)
>>> {
>>>  int D.1364;
>>>
>>>  D.1364 = i;
>>>  i = D.1364 + 1;
>>>  arr[D.1364] = i;
>>> }
>>>
>>> which looks to me from description of the C-specification correct.
>>
>> Hm, indeed.  I'll test the following shorter patch and add the struct-return
>> volatile testcase.
>
> Works apart from
>
> Running target unix/
> FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test
> FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test
>
> Maybe invalid testcases.  Who knows ... same fails happen with your patch.
>
> Richard.
>
>> Richard.

Hmm, I see in libstdc++'s file include/bits/boost_concept_check.h some
use of '*__i++ = *__i;' and '*__i-- = *__i;', which seems to cause
part of this failure.

This might lead here to this failure.  I am not sure, if such
constructs having fixed behavior for C++, but it looks to me like
undefined behavior.

A C-testcase for the issue would be:

int *foo (int *p)
{
  *p++ = *p;
  return p;
}

which produces with patch now:

foo (int * p)
{
  int * D.1363;
  int D.1364;
  int * D.1365;

  D.1363 = p;
  p = D.1363 + 4;
  D.1364 = *p;
  *D.1363 = D.1364;
  D.1365 = p;
  return D.1365;
}

but in old variant we were producing:

foo (int * p)
{
  int D.1363;
  int * D.1364;

  D.1363 = *p;
  *p = D.1363;
  p = p + 4;
  D.1364 = p;
  return D.1364;
}

So, maybe the real solution for this issue might be to swap for
assignment gimplification the order for lhs/rhs gimplification
instead.


Regards,
Kai
Richard Biener Feb. 10, 2012, 10:35 a.m. UTC | #8
On Fri, Feb 10, 2012 at 9:36 AM, Kai Tietz <ktietz70@googlemail.com> wrote:
> 2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
>> Works apart from
>>
>> Running target unix/
>> FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test
>> FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test
>>
>> Maybe invalid testcases.  Who knows ... same fails happen with your patch.
>>
>> Richard.
>>
>>> Richard.
>
> Hmm, I see in libstdc++'s file include/bits/boost_concept_check.h some
> use of '*__i++ = *__i;' and '*__i-- = *__i;', which seems to cause
> part of this failure.
>
> This might lead here to this failure.  I am not sure, if such
> constructs having fixed behavior for C++, but it looks to me like
> undefined behavior.
>
> A C-testcase for the issue would be:
>
> int *foo (int *p)
> {
>  *p++ = *p;
>  return p;
> }
>
> which produces with patch now:
>
> foo (int * p)
> {
>  int * D.1363;
>  int D.1364;
>  int * D.1365;
>
>  D.1363 = p;
>  p = D.1363 + 4;
>  D.1364 = *p;
>  *D.1363 = D.1364;
>  D.1365 = p;
>  return D.1365;
> }
>
> but in old variant we were producing:
>
> foo (int * p)
> {
>  int D.1363;
>  int * D.1364;
>
>  D.1363 = *p;
>  *p = D.1363;
>  p = p + 4;
>  D.1364 = p;
>  return D.1364;
> }
>
> So, maybe the real solution for this issue might be to swap for
> assignment gimplification the order for lhs/rhs gimplification
> instead.

Well, that would certainly not be suitable for stage4 (though I have a working
patch for that as well).  The post-modify gimplification change looks better
as it also fixes the volatile aggregate-return case which would not be fixed
by re-ordering of the gimplification.

libstdc++ folks - can you investigate the testsuite failure?

The patch in question is at
http://gcc.gnu.org/ml/gcc-patches/2012-02/msg00435/fix-pr48814

Note that the _Mutable_ForwardIteratorConcept isn't the problem I think,
it's not executed code.

Thanks,
Richard.

>
> Regards,
> Kai
Andreas Schwab Feb. 10, 2012, 12:30 p.m. UTC | #9
Kai Tietz <ktietz70@googlemail.com> writes:

> Hmm, I see in libstdc++'s file include/bits/boost_concept_check.h some
> use of '*__i++ = *__i;' and '*__i-- = *__i;', which seems to cause
> part of this failure.

I don't think those __constraints functions are ever executed.  They are
only present to assert the presense of certain operations at compile
time.

Andreas.
Jonathan Wakely Feb. 10, 2012, 1:12 p.m. UTC | #10
On 10 February 2012 10:35, Richard Guenther wrote:
>>> Works apart from
>>>
>>> Running target unix/
>>> FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test
>>> FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test

What does libstdc++.log show for those failures?
Richard Biener Feb. 10, 2012, 1:28 p.m. UTC | #11
On Fri, Feb 10, 2012 at 2:12 PM, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 10 February 2012 10:35, Richard Guenther wrote:
>>>> Works apart from
>>>>
>>>> Running target unix/
>>>> FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test
>>>> FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test
>
> What does libstdc++.log show for those failures?

spawn [open ...]^M
<?xml version = "1.0"?>
<test>
<sd value = "1328880244">
</sd>
<n value = "5000">
</n>
<m value = "10000">
</m>
<tp value = "0.2">
</tp>
<ip value = "0.6">
</ip>
<ep value = "0.2">
</ep>
<cp value = "0.001">
</cp>
<mp value = "0.25">
</mp>
</test>
<cntnr name = "pat_trie_map">
<desc>
<type value = "trie">
<Tag value = "pat_trie_tag">
</Tag>
<Node_Update value = "null_node_update">
</Node_Update>
</type>
</desc>
<progress>
----------------------------------------
*FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test

spawn [open ...]^M
<?xml version = "1.0"?>
<test>
<sd value = "1328880487">
</sd>
<n value = "5000">
</n>
<m value = "10000">
</m>
<tp value = "0.2">
</tp>
<ip value = "0.6">
</ip>
<ep value = "0.2">
</ep>
<cp value = "0.001">
</cp>
<mp value = "0.25">
</mp>
</test>
<cntnr name = "pat_trie_set">
<desc>
<type value = "trie">
<Tag value = "pat_trie_tag">
</Tag>
<Node_Update value = "null_node_update">
</Node_Update>
</type>
</desc>
<progress>
----------------------------------------
**FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test
Kai Tietz Feb. 10, 2012, 3:11 p.m. UTC | #12
2012/2/10 Richard Guenther <richard.guenther@gmail.com>:
> On Fri, Feb 10, 2012 at 9:36 AM, Kai Tietz <ktietz70@googlemail.com> wrote:
>> 2012/2/9 Richard Guenther <richard.guenther@gmail.com>:
>>> Works apart from
>>>
>>> Running target unix/
>>> FAIL: ext/pb_ds/regression/trie_map_rand.cc execution test
>>> FAIL: ext/pb_ds/regression/trie_set_rand.cc execution test
>>>
>>> Maybe invalid testcases.  Who knows ... same fails happen with your patch.
>>>
>>> Richard.
>>>
>>>> Richard.
>>
>> Hmm, I see in libstdc++'s file include/bits/boost_concept_check.h some
>> use of '*__i++ = *__i;' and '*__i-- = *__i;', which seems to cause
>> part of this failure.
>>
>> This might lead here to this failure.  I am not sure, if such
>> constructs having fixed behavior for C++, but it looks to me like
>> undefined behavior.
>>
>> A C-testcase for the issue would be:
>>
>> int *foo (int *p)
>> {
>>  *p++ = *p;
>>  return p;
>> }
>>
>> which produces with patch now:
>>
>> foo (int * p)
>> {
>>  int * D.1363;
>>  int D.1364;
>>  int * D.1365;
>>
>>  D.1363 = p;
>>  p = D.1363 + 4;
>>  D.1364 = *p;
>>  *D.1363 = D.1364;
>>  D.1365 = p;
>>  return D.1365;
>> }
>>
>> but in old variant we were producing:
>>
>> foo (int * p)
>> {
>>  int D.1363;
>>  int * D.1364;
>>
>>  D.1363 = *p;
>>  *p = D.1363;
>>  p = p + 4;
>>  D.1364 = p;
>>  return D.1364;
>> }
>>
>> So, maybe the real solution for this issue might be to swap for
>> assignment gimplification the order for lhs/rhs gimplification
>> instead.
>
> Well, that would certainly not be suitable for stage4 (though I have a working
> patch for that as well).  The post-modify gimplification change looks better
> as it also fixes the volatile aggregate-return case which would not be fixed
> by re-ordering of the gimplification.
>
> libstdc++ folks - can you investigate the testsuite failure?
>
> The patch in question is at
> http://gcc.gnu.org/ml/gcc-patches/2012-02/msg00435/fix-pr48814
>
> Note that the _Mutable_ForwardIteratorConcept isn't the problem I think,
> it's not executed code.
>
> Thanks,
> Richard.

Hmm, we might need here lhs/rhs flip plus the post-modify.  At least
we would avoid by this code differences for common cases that lhs has
post-inc/dec to current behavior?

But you might be right that this patch is not suitable for stage 4.

Regards,
Kai
Kai Tietz March 15, 2012, 3:22 p.m. UTC | #13
Richard,

ping.  I think now could be a good time for applying the patch you
have for this issue as we are in stage 1.

Regards,
Kai
Richard Biener March 15, 2012, 3:40 p.m. UTC | #14
On Thu, Mar 15, 2012 at 4:22 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
> Richard,
>
> ping.  I think now could be a good time for applying the patch you
> have for this issue as we are in stage 1.

It will still regress the two libstdc++ testcases (well, I guess so at least).

Jonathan - you didn't answer my reply to your question?  Would it be ok
to apply this patch with leaving the regressions in-place, to be investigated
by libstdc++ folks?

Thanks,
Richard.

> Regards,
> Kai
Jonathan Wakely March 16, 2012, 12:29 a.m. UTC | #15
On 15 March 2012 15:40, Richard Guenther wrote:
> On Thu, Mar 15, 2012 at 4:22 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>> Richard,
>>
>> ping.  I think now could be a good time for applying the patch you
>> have for this issue as we are in stage 1.
>
> It will still regress the two libstdc++ testcases (well, I guess so at least).
>
> Jonathan - you didn't answer my reply to your question?  Would it be ok
> to apply this patch with leaving the regressions in-place, to be investigated
> by libstdc++ folks?

Sorry, I've either forgotten or missed the reply - but if you think
the problem is in libstdc++ then certainly go ahead and apply it, I'll
investigate the libstdc++ problems (and ask for help if they defeat
me!)
Richard Biener March 16, 2012, 10:10 a.m. UTC | #16
On Fri, Mar 16, 2012 at 1:29 AM, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 15 March 2012 15:40, Richard Guenther wrote:
>> On Thu, Mar 15, 2012 at 4:22 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>> Richard,
>>>
>>> ping.  I think now could be a good time for applying the patch you
>>> have for this issue as we are in stage 1.
>>
>> It will still regress the two libstdc++ testcases (well, I guess so at least).
>>
>> Jonathan - you didn't answer my reply to your question?  Would it be ok
>> to apply this patch with leaving the regressions in-place, to be investigated
>> by libstdc++ folks?
>
> Sorry, I've either forgotten or missed the reply - but if you think
> the problem is in libstdc++ then certainly go ahead and apply it, I'll
> investigate the libstdc++ problems (and ask for help if they defeat
> me!)

Ok.  I'll do so after re-testing the patch.

Richard.
diff mbox

Patch

Index: gcc/gcc/gimplify.c
===================================================================
--- gcc.orig/gcc/gimplify.c
+++ gcc/gcc/gimplify.c
@@ -2197,7 +2197,7 @@  gimplify_self_mod_expr (tree *expr_p, gi
 			bool want_value)
 {
   enum tree_code code;
-  tree lhs, lvalue, rhs, t1;
+  tree lhs, lvalue, rhs, t1, t2;
   gimple_seq post = NULL, *orig_post_p = post_p;
   bool postfix;
   enum tree_code arith_code;
@@ -2264,20 +2264,23 @@  gimplify_self_mod_expr (tree *expr_p, gi
       arith_code = POINTER_PLUS_EXPR;
     }

-  t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
-
-  if (postfix)
-    {
-      gimplify_assign (lvalue, t1, orig_post_p);
-      gimplify_seq_add_seq (orig_post_p, post);
-      *expr_p = lhs;
-      return GS_ALL_DONE;
-    }
-  else
+  if (!postfix)
     {
+      t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
       *expr_p = build2 (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
       return GS_OK;
     }
+
+  /* Assign lhs to temporary variable.  */
+  t2 = create_tmp_var (TREE_TYPE (lhs), NULL);
+  gimplify_assign (t2, lhs, pre_p);
+  /* Do increment and assign it to lvalue.  */
+  t1 = build2 (arith_code, TREE_TYPE (*expr_p), t2, rhs);
+  gimplify_assign (lvalue, t1, pre_p);
+
+  gimplify_seq_add_seq (orig_post_p, post);
+  *expr_p = t2;
+  return GS_ALL_DONE;
 }

 /* If *EXPR_P has a variable sized type, wrap it in a WITH_SIZE_EXPR.  */
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-1.c
@@ -0,0 +1,18 @@ 
+extern void abort (void);
+
+int arr[] = {1,2,3,4};
+int count = 0;
+
+int __attribute__((noinline))
+incr (void)
+{
+  return ++count;
+}
+
+int main()
+{
+  arr[count++] = incr ();
+  if (count != 2 || arr[count] != 3)
+    abort ();
+  return 0;
+}
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pr48814-2.c
@@ -0,0 +1,18 @@ 
+extern void abort (void);
+
+int arr[] = {1,2,3,4};
+int count = 0;
+
+int
+incr (void)
+{
+  return ++count;
+}
+
+int main()
+{
+  arr[count++] = incr ();
+  if (count != 2 || arr[count] != 3)
+    abort ();
+  return 0;
+}
Index: gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-1.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+volatile int count;
+void bar(int);
+void foo()
+{
+ bar(count++);
+}
+
+/* { dg-final { scan-tree-dump-times "count =" 1 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/tree-ssa/assign-2.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+volatile int count;
+int arr[4];
+void foo()
+{
+ arr[count++] = 0;
+}
+
+/* { dg-final { scan-tree-dump-times "count =" 1 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+