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

            Bug ID: 117935
           Summary: [[likely]] attribute not propagated from function body
                    to callers
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

Given:

struct optional
{
    union {
        int val;
    };
    bool has_val = false;

    bool has_value(bool b) const {
#ifdef HINT
        return __builtin_expect(b,1);
#else
        if (b)
#ifdef LIKELY
        [[likely]]
#endif
            return true;
        else
            return false;
#endif
    }

    int value_or(int def) const
    {
        if (has_value(has_val))
            return val;
        else
            return def;
    }
};

int f(optional const& o) {
    return o.value_or(0);
}


This compiles to:

f(optional const&):
        xor     eax, eax
        cmp     BYTE PTR [rdi+4], 0
        je      .L1
        mov     eax, DWORD PTR [rdi]
.L1:
        ret

Defining LIKELY doesn't change anything, so the [[likely]] attribute inside the
has_value() function doesn't seem to do anything.

But defining HINT gives this different code:

f(optional const&):
        cmp     BYTE PTR [rdi+4], 0
        je      .L3
        mov     eax, DWORD PTR [rdi]
        ret
.L3:
        xor     eax, eax
        ret

It looks like the value_or function uses the __builtin_expect hint so that the
xor is moved into the unlikely path.



The gimple for -DHINT looks like:

bool optional::has_value (const struct optional * const this, bool b)
{
  bool D.2871;

  # DEBUG BEGIN_STMT
  _1 = (long int) b;
  _2 = __builtin_expect (_1, 1);
  D.2871 = _2 != 0;
  return D.2871;
}

And for -DLIKELY it looks like:

bool optional::has_value (const struct optional * const this, bool b)
{
  bool D.2873;

  # DEBUG BEGIN_STMT
  if (b != 0) goto <D.2871>; else goto <D.2872>;
  <D.2871>:
  # DEBUG BEGIN_STMT
  // predicted likely by hot label predictor.
  D.2873 = 1;
  // predicted unlikely by early return (on trees) predictor.
  return D.2873;
  <D.2872>:
  # DEBUG BEGIN_STMT
  D.2873 = 0;
  // predicted unlikely by early return (on trees) predictor.
  return D.2873;
  __builtin_unreachable ();
}

Is it expected that the hot label predictor has no effect on the callers?

Reply via email to