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.

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.

Without looking at the patch in detail there is two things. The memcpy problem may be related to the problems we had with placement new, though unfortunately with different semantics. You have to assume that a pointer passed to a function is written to through a different effective type as the pointed-to-type of the argument.

Another thing is that the novops attribute was exposed to users, so I believe we
should not take it away without the usual deprecation period of one
release.  Can
you simply map it back to a signature?

The setting of a signature is not exposed to the user right now?
Would it be possible
to do that to be able to annotate more library functions?  I
originally had thought
about __attribute__((noescape(n,m,...))) and
__attribute__((noclobber(n,m,...))) and
storing a bitmap for both properties somewhere.

Thanks,
Richard.

Zdenek

        * tree.h (DEF_BUILTIN): Add SIG argument.
        (DECL_IS_NOVOPS): Removed.
        (DECL_SIGNATURE): New.
        (struct function_signature): New type.
        (struct tree_function_decl): Remove novops_flag, add sig field.
        (ECF_NOVOPS): Removed.
        * builtins.c (DEF_BUILTIN): Add SIG argument.
        * builtin-attrs.def: Remove NOVOPS attribute and corresponding
        attribute lists.
        * builtins.def: Replace NOVOPS attribute by signature.  Add signatures
        for string functions.
        * tree-ssa-alias.c (count_derefs_in_call): New function.
        (count_uses_and_derefs): Use count_derefs_in_call.
        (is_escape_site): Functions with signature are not escape sites.
        * c-decl.c (merge_decls): Do not copy DECL_IS_NOVOPS.  Copy
        DECL_SIGNATURE.
        * calls.c (flags_from_decl_or_type): Do not handle DECL_IS_NOVOPS.
        * tree-ssa-loop-prefetch.c (tree_ssa_prefetch_arrays): Set signature
        for builtin_prefetch instead of DECL_IS_NOVOPS.
        * tree-vect-transform.c (novops_signature_p): New function.
        (vectorizable_function): Use novops_signature_p instead of testing
        for ECF_NOVOPS.
        * c-common.c (handle_novops_attribute): Removed.
        (c_common_attributes): Remove NOVOPS attribute.
        (def_builtin_1): Set DECL_SIGNATURE for the created decls.
        (DEF_BUILTIN): Pass signature to def_builtin_1.
        (parse_builtin_signature): New function.
        * tree-ssa-operands.c (get_ptr_operands): Split from ...
        (get_indirect_ref_operands): ... here.
        (find_errno_decl, add_call_signature_operands): New functions.
        (get_call_expr_operands): Call add_call_signature_operands for
        functions with signature.

* gcc.dg/tree-prof/stringop-1.c: Update outcome.


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