Hi,
this patch works around PR where we refuse to inline always_inline memcpy
into function with explicit Ofast optimization attribute.  This is because
we think we can not promote -fno-fast-math code to -fast-math code.
This is of course safe for memcpy because it contains to fast-math code,
but we don't really do the analysis for each of the flags we check.

Earlier compilers was happily producing wrong code here and it seems practical
to do that on GCC 5 to deal with common falout.  I will implement the more
fine grained check incrementally.

Bootstrapped/regtested x86_64-linux. Will commit it to mainline shortly and
to release branch later this week.

        PR ipa/65873
        * ipa-inline.c (can_inline_edge_p): Allow early inlining of always
        inlines across optimization boundary.
        * testsuite/gcc.c-torture/compile/pr65873.c: New testcase.
Index: ipa-inline.c
===================================================================
--- ipa-inline.c        (revision 223093)
+++ ipa-inline.c        (working copy)
@@ -427,46 +427,55 @@ can_inline_edge_p (struct cgraph_edge *e
              && lookup_attribute ("always_inline",
                                   DECL_ATTRIBUTES (callee->decl)));
 
+     /* Until GCC 4.9 we did not check the semantics alterning flags
+       bellow and inline across optimization boundry.
+       Enabling checks bellow breaks several packages by refusing
+       to inline library always_inline functions. See PR65873.
+       Disable the check for early inlining for now until better solution
+       is found.  */
+     if (always_inline && early)
+       ;
       /* There are some options that change IL semantics which means
          we cannot inline in these cases for correctness reason.
         Not even for always_inline declared functions.  */
       /* Strictly speaking only when the callee contains signed integer
          math where overflow is undefined.  */
-      if ((check_maybe_up (flag_strict_overflow)
-          /* this flag is set by optimize.  Allow inlining across
-             optimize boundary.  */
-          && (!opt_for_fn (caller->decl, optimize)
-              == !opt_for_fn (callee->decl, optimize) || !always_inline))
-         || check_match (flag_wrapv)
-         || check_match (flag_trapv)
-         /* Strictly speaking only when the callee uses FP math.  */
-         || check_maybe_up (flag_rounding_math)
-         || check_maybe_up (flag_trapping_math)
-         || check_maybe_down (flag_unsafe_math_optimizations)
-         || check_maybe_down (flag_finite_math_only)
-         || check_maybe_up (flag_signaling_nans)
-         || check_maybe_down (flag_cx_limited_range)
-         || check_maybe_up (flag_signed_zeros)
-         || check_maybe_down (flag_associative_math)
-         || check_maybe_down (flag_reciprocal_math)
-         /* We do not want to make code compiled with exceptions to be brought
-            into a non-EH function unless we know that the callee does not
-            throw.  This is tracked by DECL_FUNCTION_PERSONALITY.  */
-         || (check_match (flag_non_call_exceptions)
-             /* TODO: We also may allow bringing !flag_non_call_exceptions
-                to flag_non_call_exceptions function, but that may need
-                extra work in tree-inline to add the extra EH edges.  */
-             && (!opt_for_fn (callee->decl, flag_non_call_exceptions)
-                 || DECL_FUNCTION_PERSONALITY (callee->decl)))
-         || (check_maybe_up (flag_exceptions)
-             && DECL_FUNCTION_PERSONALITY (callee->decl))
-         /* Strictly speaking only when the callee contains function
-            calls that may end up setting errno.  */
-         || check_maybe_up (flag_errno_math)
-         /* When devirtualization is diabled for callee, it is not safe
-            to inline it as we possibly mangled the type info.
-            Allow early inlining of always inlines.  */
-         || (!early && check_maybe_down (flag_devirtualize)))
+     else if ((check_maybe_up (flag_strict_overflow)
+              /* this flag is set by optimize.  Allow inlining across
+                 optimize boundary.  */
+              && (!opt_for_fn (caller->decl, optimize)
+                  == !opt_for_fn (callee->decl, optimize) || !always_inline))
+             || check_match (flag_wrapv)
+             || check_match (flag_trapv)
+             /* Strictly speaking only when the callee uses FP math.  */
+             || check_maybe_up (flag_rounding_math)
+             || check_maybe_up (flag_trapping_math)
+             || check_maybe_down (flag_unsafe_math_optimizations)
+             || check_maybe_down (flag_finite_math_only)
+             || check_maybe_up (flag_signaling_nans)
+             || check_maybe_down (flag_cx_limited_range)
+             || check_maybe_up (flag_signed_zeros)
+             || check_maybe_down (flag_associative_math)
+             || check_maybe_down (flag_reciprocal_math)
+             /* We do not want to make code compiled with exceptions to be
+                brought into a non-EH function unless we know that the callee
+                does not throw.
+                This is tracked by DECL_FUNCTION_PERSONALITY.  */
+             || (check_match (flag_non_call_exceptions)
+                 /* TODO: We also may allow bringing !flag_non_call_exceptions
+                    to flag_non_call_exceptions function, but that may need
+                    extra work in tree-inline to add the extra EH edges.  */
+                 && (!opt_for_fn (callee->decl, flag_non_call_exceptions)
+                     || DECL_FUNCTION_PERSONALITY (callee->decl)))
+             || (check_maybe_up (flag_exceptions)
+                 && DECL_FUNCTION_PERSONALITY (callee->decl))
+             /* Strictly speaking only when the callee contains function
+                calls that may end up setting errno.  */
+             || check_maybe_up (flag_errno_math)
+             /* When devirtualization is diabled for callee, it is not safe
+                to inline it as we possibly mangled the type info.
+                Allow early inlining of always inlines.  */
+             || (!early && check_maybe_down (flag_devirtualize)))
        {
          e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
          inlinable = false;
@@ -481,6 +490,17 @@ can_inline_edge_p (struct cgraph_edge *e
          e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
          inlinable = false;
        }
+      /* If explicit optimize attribute are not used, the mismatch is caused
+        by different command line options used to build different units.
+        Do not care about COMDAT functions - those are intended to be
+         optimized with the optimization flags of module they are used in.
+        Also do not care about mixing up size/speed optimization when
+        DECL_DISREGARD_INLINE_LIMITS is set.  */
+      else if ((callee->merged
+               && !lookup_attribute ("optimize",
+                                     DECL_ATTRIBUTES (caller->decl)))
+              || DECL_DISREGARD_INLINE_LIMITS (callee->decl))
+       ;
       /* If mismatch is caused by merging two LTO units with different
         optimizationflags we want to be bit nicer.  However never inline
         if one of functions is not optimized at all.  */
Index: testsuite/gcc.c-torture/compile/pr65873.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr65873.c   (revision 0)
+++ testsuite/gcc.c-torture/compile/pr65873.c   (revision 0)
@@ -0,0 +1,14 @@
+typedef __SIZE_TYPE__ size_t;
+
+extern inline __attribute__ ((__always_inline__, __gnu_inline__, 
__artificial__, __nothrow__, __leaf__)) void *
+memcpy (void *__restrict __dest, const void *__restrict __src, size_t __len)
+{
+  return __builtin___memcpy_chk (__dest, __src, __len, __builtin_object_size 
(__dest, 0));
+}
+
+__attribute__((optimize ("Ofast"))) void
+bar (void *d, void *s, size_t l)
+{
+  memcpy (d, s, l);
+}
+

Reply via email to