This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Don't optimize builtins declared always_inline until after inlining (PR middle-end/38454, take 2)
On Tue, Dec 9, 2008 at 11:13 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> Here is an updated patch that hopefully addresses the things you've raised
> here and on IRC. Honza said on IRC unless always_inline functions
> are recursive and similar weirdnesses that after early inlining (when -O1+)
> always_inline functions should be inlined.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
Ok.
Thanks,
Richard.
> 2008-12-09 Jakub Jelinek <jakub@redhat.com>
>
> PR middle-end/38454
> * function.h (struct function): Add always_inline_functions_inlined.
> * ipa-inline.c (cgraph_early_inlining): Set it to true.
> * tree-optimize.c (execute_fixup_cfg): Likewise.
> * builtins.c (avoid_folding_inline_builtin): New function.
> (fold_call_expr): Don't optimize always_inline builtins before
> inlining.
> (fold_call_stmt): Likewise.
> (fold_builtin_call_array): Likewise. Don't call
> fold_builtin_varargs for BUILT_IN_MD builtins.
>
> * gcc.dg/memset-1.c: New test.
> * gcc.dg/memcpy-2.c: New test.
>
> --- gcc/ipa-inline.c.jj 2008-09-30 16:57:11.000000000 +0200
> +++ gcc/ipa-inline.c 2008-12-09 21:41:43.000000000 +0100
> @@ -1528,6 +1528,7 @@ cgraph_early_inlining (void)
> todo = optimize_inline_calls (current_function_decl);
> timevar_pop (TV_INTEGRATION);
> }
> + cfun->always_inline_functions_inlined = true;
> return todo;
> }
>
> --- gcc/function.h.jj 2008-09-30 16:57:11.000000000 +0200
> +++ gcc/function.h 2008-12-09 21:39:14.000000000 +0100
> @@ -578,6 +578,7 @@ struct function GTY(())
> unsigned int dont_save_pending_sizes_p : 1;
>
> unsigned int after_inlining : 1;
> + unsigned int always_inline_functions_inlined : 1;
>
> /* Fields below this point are not set for abstract functions; see
> allocate_struct_function. */
> --- gcc/tree-optimize.c.jj 2008-09-30 16:57:11.000000000 +0200
> +++ gcc/tree-optimize.c 2008-12-09 21:42:06.000000000 +0100
> @@ -293,6 +293,7 @@ execute_fixup_cfg (void)
> int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
>
> cfun->after_inlining = true;
> + cfun->always_inline_functions_inlined = true;
>
> if (cfun->eh)
> FOR_EACH_BB (bb)
> --- gcc/builtins.c.jj 2008-12-09 16:48:24.000000000 +0100
> +++ gcc/builtins.c 2008-12-09 21:48:57.000000000 +0100
> @@ -10797,6 +10797,22 @@ fold_builtin_varargs (tree fndecl, tree
> return NULL_TREE;
> }
>
> +/* Return true if FNDECL shouldn't be folded right now.
> + If a built-in function has an inline attribute always_inline
> + wrapper, defer folding it after always_inline functions have
> + been inlined, otherwise e.g. -D_FORTIFY_SOURCE checking
> + might not be performed. */
> +
> +static bool
> +avoid_folding_inline_builtin (tree fndecl)
> +{
> + return (DECL_DECLARED_INLINE_P (fndecl)
> + && DECL_DISREGARD_INLINE_LIMITS (fndecl)
> + && cfun
> + && !cfun->always_inline_functions_inlined
> + && lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)));
> +}
> +
> /* A wrapper function for builtin folding that prevents warnings for
> "statement without effect" and the like, caused by removing the
> call node earlier than the warning is generated. */
> @@ -10829,6 +10845,9 @@ fold_call_expr (tree exp, bool ignore)
> return NULL_TREE;
> }
>
> + if (avoid_folding_inline_builtin (fndecl))
> + return NULL_TREE;
> +
> /* FIXME: Don't use a list in this interface. */
> if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
> return targetm.fold_builtin (fndecl, CALL_EXPR_ARGS (exp), ignore);
> @@ -10931,6 +10950,8 @@ fold_builtin_call_array (tree type,
> && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
> return build_call_array (type, fn, n, argarray);
> }
> + if (avoid_folding_inline_builtin (fndecl))
> + return build_call_array (type, fn, n, argarray);
> if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
> {
> tree arglist = NULL_TREE;
> @@ -10939,6 +10960,7 @@ fold_builtin_call_array (tree type,
> ret = targetm.fold_builtin (fndecl, arglist, false);
> if (ret)
> return ret;
> + return build_call_array (type, fn, n, argarray);
> }
> else if (n <= MAX_ARGS_TO_FOLD_BUILTIN)
> {
> @@ -13647,6 +13669,8 @@ fold_call_stmt (gimple stmt, bool ignore
> {
> int nargs = gimple_call_num_args (stmt);
>
> + if (avoid_folding_inline_builtin (fndecl))
> + return NULL_TREE;
> /* FIXME: Don't use a list in this interface. */
> if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
> {
> --- gcc/testsuite/gcc.dg/memcpy-2.c.jj 2008-12-09 16:50:28.000000000 +0100
> +++ gcc/testsuite/gcc.dg/memcpy-2.c 2008-12-09 16:50:28.000000000 +0100
> @@ -0,0 +1,25 @@
> +/* PR middle-end/38454 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +typedef __SIZE_TYPE__ size_t;
> +
> +extern inline __attribute__((gnu_inline, always_inline, artificial)) void *
> +memcpy (void *__restrict dest, const void *__restrict src, size_t len)
> +{
> + return __builtin___memcpy_chk (dest, /* { dg-warning "will always overflow destination buffer" } */
> + src, len, __builtin_object_size (dest, 0));
> +}
> +
> +struct S { char buf[10]; } s;
> +
> +void
> +foo (void)
> +{
> + char buf[12];
> + char *p = buf + 4;
> + struct S *q = (struct S *) p;
> + memcpy (q, &s, sizeof (s));
> +}
> +
> +/* { dg-final { scan-assembler "__memcpy_chk" } } */
> --- gcc/testsuite/gcc.dg/memset-1.c.jj 2008-12-09 16:50:28.000000000 +0100
> +++ gcc/testsuite/gcc.dg/memset-1.c 2008-12-09 16:50:28.000000000 +0100
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +typedef __SIZE_TYPE__ size_t;
> +
> +extern void warn_memset_zero_len (void)
> +__attribute__((__warning__ ("memset used with constant zero length parameter;"
> + " this could be due to transposed parameters")));
> +
> +extern inline __attribute__((gnu_inline, always_inline, artificial)) void *
> +memset (void *dest, int ch, size_t len)
> +{
> + if (__builtin_constant_p (len) && len == 0)
> + {
> + warn_memset_zero_len (); /* { dg-warning "memset used with constant zero" } */
> + return dest;
> + }
> + return __builtin_memset (dest, ch, len);
> +}
> +
> +char buf[10];
> +
> +int
> +main (void)
> +{
> + memset (buf, sizeof (buf), 0);
> + return 0;
> +}
>
> Jakub
>