Bug 19637 - Missed VRP and FRE opportunities in the presence of casts
Summary: Missed VRP and FRE opportunities in the presence of casts
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.0.0
: P2 enhancement
Target Milestone: 4.4.0
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on:
Blocks:
 
Reported: 2005-01-26 12:25 UTC by Richard Biener
Modified: 2008-03-17 15:03 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2005-06-13 04:26:30


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2005-01-26 12:25:56 UTC
For the following testcase with three similar functions we do different
tree optimizations:

#include <new>

struct Foo {
        Foo() { i[0] = 1; }
        int i[2];
};

int foo_char(void)
{
        int i[2];
        new (reinterpret_cast<char *>(i)) Foo();
        return reinterpret_cast<Foo *>(i)->i[0];
}

int foo_void(void)
{
        int i[2];
        new (reinterpret_cast<void *>(i)) Foo();
        return reinterpret_cast<Foo *>(i)->i[0];
}

int foo_void_offset(void)
{
        int i[2];
        new (reinterpret_cast<void *>(&i[0])) Foo();
        return reinterpret_cast<Foo *>(&i[0])->i[0];
}

We only can optimize the foo_void_offset() variant to return 1, the
foo_void() variant results in

<bb 0>:
  this = (struct Foo *) &i[0];
  this->i[0] = 1;
  i.6 = (struct Foo *) &i;
  return i.6->i[0];

where the difference starts in what the frontend produces:

  (void) (TARGET_EXPR <D.1791, (struct Foo *) operator new (8, (void *) &i[0])>;
and return <retval> = ((struct Foo *) &i[0])->i[0];

vs.   (void) (TARGET_EXPR <D.1783, (struct Foo *) operator new (8, (void *) (int
*) &i)>;
and return <retval> = ((struct Foo *) (int *) &i)->i[0];

note that mixing &i[0] and i does not allow folding.


For the char* variant we even cannot prove that &i is non-null (!?):

<bb 0>:
  i.2 = (char *) &i;
  __p = i.2;
  this = (struct Foo *) __p;
  if (__p != 0B) goto <L1>; else goto <L3>;

<L1>:;
  this->i[0] = 1;

<L3>:;
  i.4 = (struct Foo *) &i;
  return i.4->i[0];

though this might be somehow related to type-based aliasing rules(?).
Note that the char variant does not care if &i[0] or plain i is specified.
Comment 1 Richard Biener 2005-02-10 09:39:41 UTC
It's CCP that for foo_void is able to propagate &i[0] into the comparison here:

  struct Foo * const this;
  void * D.1798;
  size_t D.1795;
  void * __p;
  int i[2];
  struct Foo * i.6;
  int D.1786;
  struct Foo * iftmp.5;
  void * D.1784;
  struct Foo * D.1783;

<bb 0>:
  __p_2 = &i[0];
  this_6 = (struct Foo *) __p_2;
  if (__p_2 != 0B) goto <L1>; else goto <L3>;


but not for foo_char, as here:

  struct Foo * const this;
  void * D.1821;
  size_t D.1818;
  void * __p;
  int i[2];
  struct Foo * i.4;
  int D.1778;
  struct Foo * iftmp.3;
  void * D.1776;
  char * i.2;
  struct Foo * D.1765;

<bb 0>:
  i.2_1 = (char *) &i;
  __p_3 = i.2_1;
  this_7 = (struct Foo *) __p_3;
  if (__p_3 != 0B) goto <L1>; else goto <L3>;


I guess CCP is confused by the cast.  So much for the char*/void* difference.
Comment 2 Richard Biener 2005-02-10 09:49:02 UTC
The difference between foo_void and foo_void_offset is that for foo_void PRE
cannot see that (struct Foo *) &i[0] is equivalent to (struct Foo *) &i.  As
such, for foo_void we end up with

<bb 0>:
  __p_2 = &i[0];
  this_6 = (struct Foo *) &i[0];
  this_6->i[0] = 1;

<L3>:;
  i.3_7 = (struct Foo *) &i;
  D.1777_8 = i.3_7->i[0];
  return D.1777_8;

while for foo_void_offset the two uses of i are redundant and one is
removed:

<bb 0>:
  __p_2 = &i[0];
  this_6 = (struct Foo *) &i[0];
  this_6->i[0] = 1;

<L3>:;
  D.1786_7 = this_6;
  D.1785_8 = D.1786_7->i[0];
  return D.1785_8;


So it seems we either need to teach PRE the equivalency between
(struct Foo *) &i[0] and (struct Foo *) &i, or fold should canonicalize
them to one form (which one? I guess &i[0]).
Comment 3 Richard Biener 2005-02-10 10:20:51 UTC
The C++ frontend doesn't give us the opportunity to canonicalize &i to &i[0] as
it doesn't call fold in typeck:build_address or decay_conversion.

I'm lost here.
Comment 4 Andrew Pinski 2005-04-16 16:32:48 UTC
Confirmed.
Comment 5 Giovanni Bajo 2005-04-16 16:38:45 UTC
Notice that the frontend shouldn't *ever* call fold. It's the optimizers' job 
to adjust these things.
Comment 6 Andrew Pinski 2005-09-21 01:46:30 UTC
Note these are all questionable in aliasing.
Comment 7 Richard Biener 2005-10-09 09:47:57 UTC
The non-null check is now removed for the foo_char() case by VRP (note that
the non-null check for the two viod-cases are _not_ removed by VRP but by DOM1.

The propagation of the initialization in foo_void_offset is layed ground
for by FRE, which changes

  iftmp.3_6 = (struct Foo *) __p_5;
  if (iftmp.3_6 != 0B) goto <L0>; else goto <L1>;

<L0>:;
  this_11 = (struct Foo * const) iftmp.3_6;
  this_11->i[0] = 1;
  iftmp.3_12 = iftmp.3_6;
  goto <bb 3> (<L2>);

<L1>:;
  iftmp.3_10 = iftmp.3_6;

<L2>:;
  D.2114_7 = (struct Foo *) &i[0];
  D.2113_8 = D.2114_7->i[0];
  return D.2113_8;


to


  iftmp.3_6 = (struct Foo *) __p_5;
  if (iftmp.3_6 != 0B) goto <L0>; else goto <L1>;

<L0>:;
  this_11 = iftmp.3_6;
  this_11->i[0] = 1;
  iftmp.3_12 = iftmp.3_6;
  goto <bb 3> (<L2>);

<L1>:;
  iftmp.3_10 = iftmp.3_6;
  
<L2>:; 
  D.2114_7 = iftmp.3_6;
  D.2113_8 = D.2114_7->i[0];


which can then be optimized further.  This doesn't happen for the exact
same example with void * exchanged with char * -- is FRE paying attention
to some strict-aliasing rules here?  Note there is no difference in alias
information after CCP1.

For the record, the char* example mentioned would look like

int foo_char(void)
{
        int i[2];
        new (reinterpret_cast<char *>(&i[0])) Foo();
        return reinterpret_cast<Foo *>(&i[0])->i[0];
}
Comment 8 Richard Biener 2005-10-09 09:56:11 UTC
Another one is the following (without any possible aliasing problems):

int foo_charchar(void)
{
        char i[2*sizeof(int)];
        new (i) Foo();
        return reinterpret_cast<Foo*>(&i[0])->i[0];
}

where we miss the FRE opportunity for the cast:

<bb 0>:
  iftmp.0 = (struct Foo *) &i[0];
  iftmp.0->i[0] = 1;
  D.2097 = (struct Foo *) &i[0];
  return D.2097->i[0];
Comment 9 Andrew Pinski 2006-01-08 05:35:44 UTC
(In reply to comment #8)
> Another one is the following (without any possible aliasing problems):

Actually that is still a violation of the aliasing rules, as you are acessing a character as a Foo.  Yes that is violation, though I think GCC does not define it as one.
Comment 10 Richard Biener 2006-01-08 10:35:02 UTC
(In reply to comment #9)
> Actually that is still a violation of the aliasing rules, as you are acessing a
> character as a Foo.  Yes that is violation, though I think GCC does not define
> it as one.

I think the code is fine - memory is accessed only as Foo (though it is declared
as char).  This simulates

int foo_charchar(void)
{
        void *i = alloca(2*sizeof(int));
        new (i) Foo();
        return reinterpret_cast<Foo*>(i)->i[0];
}

by making the storage explicit.
Comment 11 patchapp@dberlin.org 2007-03-05 16:30:42 UTC
Subject: Bug number PR19637

A patch for this bug has been added to the patch tracker.
The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2007-03/msg00295.html
Comment 12 Richard Biener 2008-03-17 14:35:17 UTC
Subject: Bug 19637

Author: rguenth
Date: Mon Mar 17 14:34:21 2008
New Revision: 133291

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=133291
Log:
2008-03-17  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/19637
	* fold-const.c (fold_unary): Remove restrictions of removing
	intermediate pointer-conversions (P2)(P1)P0.
	* tree-ssa-ccp.c (maybe_fold_stmt_addition): Recover from
	conversion to void pointer.
	(get_maxval_strlen): Handle addresses of the form &(*p)[0].

	* g++.dg/tree-ssa/pr19637.C: New testcase.

Added:
    trunk/gcc/testsuite/g++.dg/tree-ssa/pr19637.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/fold-const.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-ssa-ccp.c

Comment 13 Richard Biener 2008-03-17 15:03:35 UTC
Fixed.