https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116191

            Bug ID: 116191
           Summary: Avoid inlining in unlikely branches
           Product: gcc
           Version: 14.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ilija.tovilo at me dot com
  Target Milestone: ---

Note that I raised this issue on the mailing list first, but was asked to
create a bug report instead.
https://gcc.gnu.org/pipermail/gcc/2024-July/244509.html

I noticed that, in our codebase, gcc inlines some non-trivial functions in
unlikely branches, as signaled by __builtin_expect or
__builtin_expect_with_probability with any probability.

This example is adapted from php-src.

https://godbolt.org/z/aEcoKMdrr

void normal(zend_string *s) {
    zend_string_release(s);
}

__attribute__((cold)) void cold_function(zend_string *s) {
    zend_string_release(s);
}

void unlikely_branch(zend_string *s, bool cond) {
    if (__builtin_expect_with_probability(cond, 0, 0.999)) {
        zend_string_release(s);
    }
    printf("Hello world");
}

__attribute__((hot)) void unlikely_branch_in_hot_function(zend_string *s, bool
cond) {
    if (__builtin_expect_with_probability(cond, 0, 0.999)) {
        zend_string_release(s);
    }
    printf("Hello world");
}

In this particular example, zend_string_release() is inlined in all but the
cold_function(). It seems to be like there should be some threshold where gcc
avoids inlining in unlikely branches. Especially in hot functions, growing
unlikely branches may lead to more instruction cache misses. Coincidentally,
Clang does the exact opposite, inlining in cold functions, but not in unlikely
branches. What threshold that should be is unclear to me.

Note that, optimally, gcc would also avoid inlining extern inline functions in
unlikely branches, despite the inline hint, as it is the only way to allow
inlining from other compilation units.

I get this behavior on godbolt.org from gcc 10.x onward.

Of course, this is just a singular example. I don't know the details of gcc's
inlining heuristics, so please close this issue if adjusting this is not an
option.

Thank you for the wonderful compiler that is gcc!

Reply via email to