From ddb3773a1230fc16c29d8df7af3200afbab93359 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 13 May 2015 04:54:50 +0200 Subject: [PATCH] re PR ipa/65873 (Failure to inline always_inline memcpy) PR ipa/65873 * ipa-inline.c (can_inline_edge_p): Allow early inlining of always inlines across optimization boundary. From-SVN: r223107 --- gcc/ChangeLog | 6 ++++ gcc/ipa-inline.c | 90 +++++++++++++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 10b8fdd7490..3da39da22e5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2015-05-12 Jan Hubicka + + PR ipa/65873 + * ipa-inline.c (can_inline_edge_p): Allow early inlining of always + inlines across optimization boundary. + 2015-05-12 Jason Merrill * config/mmix/mmix.c, config/msp430/msp430.c: Add space between diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 017f3a50090..7fd2374bc52 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -427,46 +427,55 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, && 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, bool report, 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. */