hi,
this patch fixes bug in can_inline_edge_p where opt_for_fn is taken from
inline clone and not function being inlined into itself.  Those opt_for_fn
are going to be ignored and thus have no meaning.

I also fixed case wehre !flag_devirtualize would get inlined into
flag_devirtualize but at WPA time we possibly made changes clobbering type
information.

Bootstrapped/regtested x86_64-linux, will commit it shortly.

        * ipa-inline.c (can_inline_edge_p): Match opt_for_fn on inline
        target; also match flag_ipa_devirt.
Index: ipa-inline.c
===================================================================
--- ipa-inline.c        (revision 221076)
+++ ipa-inline.c        (working copy)
@@ -310,7 +310,7 @@ sanitize_attrs_match_for_inline_p (const
 
 static bool
 can_inline_edge_p (struct cgraph_edge *e, bool report,
-                  bool disregard_limits = false)
+                  bool disregard_limits = false, bool early = false)
 {
   bool inlinable = true;
   enum availability avail;
@@ -409,39 +409,48 @@ can_inline_edge_p (struct cgraph_edge *e
         Not even for always_inline declared functions.  */
       /* Strictly speaking only when the callee contains signed integer
          math where overflow is undefined.  */
-      if ((opt_for_fn (e->caller->decl, flag_strict_overflow)
-          != opt_for_fn (e->caller->decl, flag_strict_overflow))
-         || (opt_for_fn (e->caller->decl, flag_wrapv)
-             != opt_for_fn (e->caller->decl, flag_wrapv))
-         || (opt_for_fn (e->caller->decl, flag_trapv)
-             != opt_for_fn (e->caller->decl, flag_trapv))
+      if ((opt_for_fn (caller->decl, flag_strict_overflow)
+          != opt_for_fn (caller->decl, flag_strict_overflow))
+         || (opt_for_fn (caller->decl, flag_wrapv)
+             != opt_for_fn (caller->decl, flag_wrapv))
+         || (opt_for_fn (caller->decl, flag_trapv)
+             != opt_for_fn (caller->decl, flag_trapv))
          /* Strictly speaking only when the callee contains memory
             accesses that are not using alias-set zero anyway.  */
-         || (opt_for_fn (e->caller->decl, flag_strict_aliasing)
-             != opt_for_fn (e->caller->decl, flag_strict_aliasing))
+         || (opt_for_fn (caller->decl, flag_strict_aliasing)
+             != opt_for_fn (caller->decl, flag_strict_aliasing))
          /* Strictly speaking only when the callee uses FP math.  */
-         || (opt_for_fn (e->caller->decl, flag_rounding_math)
-             != opt_for_fn (e->caller->decl, flag_rounding_math))
-         || (opt_for_fn (e->caller->decl, flag_trapping_math)
-             != opt_for_fn (e->caller->decl, flag_trapping_math))
-         || (opt_for_fn (e->caller->decl, flag_unsafe_math_optimizations)
-             != opt_for_fn (e->caller->decl, flag_unsafe_math_optimizations))
-         || (opt_for_fn (e->caller->decl, flag_finite_math_only)
-             != opt_for_fn (e->caller->decl, flag_finite_math_only))
-         || (opt_for_fn (e->caller->decl, flag_signaling_nans)
-             != opt_for_fn (e->caller->decl, flag_signaling_nans))
-         || (opt_for_fn (e->caller->decl, flag_cx_limited_range)
-             != opt_for_fn (e->caller->decl, flag_cx_limited_range))
-         || (opt_for_fn (e->caller->decl, flag_signed_zeros)
-             != opt_for_fn (e->caller->decl, flag_signed_zeros))
-         || (opt_for_fn (e->caller->decl, flag_associative_math)
-             != opt_for_fn (e->caller->decl, flag_associative_math))
-         || (opt_for_fn (e->caller->decl, flag_reciprocal_math)
-             != opt_for_fn (e->caller->decl, flag_reciprocal_math))
+         || (opt_for_fn (caller->decl, flag_rounding_math)
+             != opt_for_fn (caller->decl, flag_rounding_math))
+         || (opt_for_fn (caller->decl, flag_trapping_math)
+             != opt_for_fn (caller->decl, flag_trapping_math))
+         || (opt_for_fn (caller->decl, flag_unsafe_math_optimizations)
+             != opt_for_fn (caller->decl, flag_unsafe_math_optimizations))
+         || (opt_for_fn (caller->decl, flag_finite_math_only)
+             != opt_for_fn (caller->decl, flag_finite_math_only))
+         || (opt_for_fn (caller->decl, flag_signaling_nans)
+             != opt_for_fn (caller->decl, flag_signaling_nans))
+         || (opt_for_fn (caller->decl, flag_cx_limited_range)
+             != opt_for_fn (caller->decl, flag_cx_limited_range))
+         || (opt_for_fn (caller->decl, flag_signed_zeros)
+             != opt_for_fn (caller->decl, flag_signed_zeros))
+         || (opt_for_fn (caller->decl, flag_associative_math)
+             != opt_for_fn (caller->decl, flag_associative_math))
+         || (opt_for_fn (caller->decl, flag_reciprocal_math)
+             != opt_for_fn (caller->decl, flag_reciprocal_math))
          /* Strictly speaking only when the callee contains function
             calls that may end up setting errno.  */
-         || (opt_for_fn (e->caller->decl, flag_errno_math)
-             != opt_for_fn (e->caller->decl, flag_errno_math)))
+         || (opt_for_fn (caller->decl, flag_errno_math)
+             != opt_for_fn (caller->decl, 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.  */
+         || (opt_for_fn (caller->decl, flag_devirtualize)
+             && !opt_for_fn (callee->decl, flag_devirtualize)
+             && (!early
+                 || (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
+                     || !lookup_attribute ("always_inline",
+                                           DECL_ATTRIBUTES (callee->decl))))))
        {
          e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
          inlinable = false;
@@ -532,7 +541,7 @@ can_early_inline_edge_p (struct cgraph_e
        fprintf (dump_file, "  edge not inlinable: not in SSA form\n");
       return false;
     }
-  if (!can_inline_edge_p (e, true))
+  if (!can_inline_edge_p (e, true, false, true))
     return false;
   return true;
 }

Reply via email to