This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch,rfh] More precise aliasing for builtins


On 7/9/07, Zdenek Dvorak <rakdver@kam.mff.cuni.cz> wrote:
Hello,

for many builtins, we currently create too pessimistic sets of virtual
operands.  For example, given the code

int a[1000], b[1000], c;

int test(void)
{
  int x;

  c = 0;
  memset (&x, 0, sizeof (x);
  memcpy (a, b, sizeof (a));
  return c + x;
}

we will consider a, b, c all modified by memcpy and memset.
Furthermore, we will consider address of x to be escaping to a call,
and thus we will consider it call clobbered (and modified by memcpy
as well).

In addition to possibly pessimizing the code, this may also complicate
optimizers; for example builtinizer may replace

for (i) a[i] = b[i];

by

memcpy (&a, &b, ...)

Now a and b become escaping to a call, so we need to rescan virtual
operands of all calls in the functions to add the references to a and b.
This is annoying (and also may prevent further optimizations).

To overcome these problems, the patch below enables us to specify a
"signature" for a builtin, that describes how it accesses memory.  For
example, memcpy has signature "n(wr)",  meaning that it does not access
any memory except through its operands ("n"), the memory pointed to by the
first operand is written and the memory pointed to by the second operand
is only read.

I"ve been meaning to do this for ages.



This patch generalizes (and replaces) the current attribute novops (novops functions now have signature "n()", instead, meaning that they do not read or write any memory).

With this information, we know that in the example above, x is only
modified by the memset, a by memcpy and c not at all.

The patch is bootstrapped & regtested on ia64.  However, there is one
regression -- gcc.c-torture/execute/20060930-2.c (testcase for PR
29272).  The problematic code looks basically this way:

struct s {struct s *x} *a, tmps;
struct t {struct t *y} *b, tmpt;

a->x = &tmps;
tmpt.y = &tmpt;
b = (struct t *) (void *) a;

memcpy (b, &tmpt, sizeof (struct s));
assert (a->x != &tmps);

With strict aliasing, we see that the accesses through a and b cannot
alias, thus concluding that the memcpy cannot affect the value of a->x.
However, this restriction does not seem to hold for memcpy.  I am not
quite sure how to fix this.

We added no_tbaa stuff to tree-ssa-structalias for placement new. This is a similar situation, where we can see it does something that would normally violate TBAA, but the standard says it is okay anyway.


What you should do is, in find_func_aliases (or thereabouts), make it look at calls, and mark the variable memcpy'd into as "no-tbaa-pruning", like we do for CHANGE_DYNAMIC_TYPE_EXPR.

This should stop it from pruning the access.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]