[patch,rfh] More precise aliasing for builtins

Richard Guenther richard.guenther@gmail.com
Mon Jul 9 16:15:00 GMT 2007


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.



More information about the Gcc-patches mailing list