https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81786

            Bug ID: 81786
           Summary: local restricted pointer can be relied on in alias
                    analysis
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

I've been looking for opportunities to improve code generation by relying on
explicit guarantees about aliasing properties that commonly hold but that GCC
cannot otherwise rely on due to the lack of contextual information.  For
instance, it's common for a function that takes a non-const pointer argument
(say Q) to modify the object it points to (say X), then call some other
function (say FOO), and then read X's value again via *Q.  Unless GCC knows the
semantics of FOO it must assume that every call to it changes the value of X,
even though it's quite rare in practice for that to happen.  It would be nice
to be able to express this guarantee to GCC to let it generate more efficient
code.

As it turns out, according to the C aliasing rules, locally declaring a
restrict-qualified pointer P as a copy of an unknown pointer Q (such as a
function argument) can be used to express the guarantee that the object X the
pointers point to isn't modified during P's lifetime.  (This is 6.7.3.1, p4.) 
So with this simple notation, GCC could rely on this guarantee to optimize the
program below as indicated in the comments.  Note that neither functions need
to make use of the restrict qualifier in its interface.  This is helpful
because relatively few functions do.

$ cat x.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout x.c
void foo (void);

void bar (int *q)
{ 
  int* restrict p = q;
  *p = 123; 

  foo ();                 // must not modify *P

  if (*p != 123)          // cannot be true
    __builtin_abort ();   // can be eliminated
}

int x;

void baz (void)
{
  x = 789;
  bar (&x);
}

;; Function bar (bar, funcdef_no=0, decl_uid=1817, cgraph_uid=0,
symbol_order=0)

bar (int * q)
{
  int _1;

  <bb 2> [100.00%] [count: INV]:
  *q_2(D) = 123;
  foo ();
  _1 = *q_2(D);
  if (_1 != 123)
    goto <bb 3>; [0.04%] [count: 0]
  else
    goto <bb 4>; [99.96%] [count: INV]

  <bb 3> [0.04%] [count: 0]:
  __builtin_abort ();

  <bb 4> [99.96%] [count: INV]:
  return;

}



;; Function baz (baz, funcdef_no=1, decl_uid=1822, cgraph_uid=1,
symbol_order=2)

baz ()
{
  int _2;

  <bb 2> [100.00%] [count: INV]:
  x = 123;
  foo ();
  _2 = x;
  if (_2 != 123)
    goto <bb 3>; [0.04%] [count: 0]
  else
    goto <bb 4>; [99.96%] [count: INV]

  <bb 3> [0.04%] [count: 0]:
  __builtin_abort ();

  <bb 4> [99.96%] [count: INV]:
  return;

}

Reply via email to