Can the use of `__builtin_expect` affect the semantics of the program?

GCC (and Clang as well), specify this __builtin_expect

for human-assisted branch prediction, as described here here . Informally, people explain their semantics as follows: "the compiler simply processes the specified branch unconditionally, and if the condition should be different than specified, an expensive rollback occurs."

But if I have a piece of code:

if (__builtin_expect(p != 0, 1)) // line 1
  p->access_object();            // line 2

      

If I were to take the informal explanation above literally, the compiler could simply execute line 2 without waiting for the condition on line 1 to be evaluated, and therefore cause undefined behavior (null pointer reversal) if the pointer happens to be null.

My question is, if I use __builtin_expect

, do I still get a guarantee that my security checks are working? And if so, can I get any runtime advantage if I use __builtin_expect

defensive checks as above?

(Note: my goal of using __builtin_expect

it like this is to get the best performance for p

non-null cases, at the cost of slowing down (even in an order of magnitude) cases where p

null, even if the latter case appears quite frequently.)

+3


source to share


1 answer


No, builtin_expect will not affect the semantics of the free program.

In particular, the compiler should not emit code that will execute the body of a block if

if that code has side effects that cannot be undone. The code should be "as if" builtin_expect

not used, other than performance.

In your specific example:

if (__builtin_expect(p != 0, 1)) // line 1
  p->access_object();            // line 2

      



p

cannot be dereferenced if it is zero. So what's the point builtin_expect

in this case? The most it can do is say that the compiler is " p

probably not null, so it access_object()

will probably be called." If the definition access_object()

is equal inline

, the compiler will probably try to inline it, whereas if you said " p

probably null", the compiler might decide that it is best not to inline the code for access_object()

the invocation at that site, as it is unlikely to be used ...

This actually leads to unintuitive usage builtin_expect

in practice: you can use to mean "this code is a slow way", no matter how "likely" it is. As a trivial example, a server program can do this:

if (__builtin_expect(is_allowed(user, request), 1))
    process(request);
else
    reject(request);

      

Even if we find that 50% of the requests are illegitimate and get rejected, we can still mark "happy path" as soon as possible, because we don't care about slowing down the bounce rate.

+4


source







All Articles