Arnout
Arnout

Reputation: 3464

Is there a way to tell GCC the range of a parameter?

I have some heavily-used code that I would like GCC to optimize aggressively. But I also want to write clean, reusable code with (inlinable) functions that are called from several places. There are cases where in the inlined function, there is code that I know can be removed because the conditions can never happen.

Let's look at a concrete example:

#include <assert.h>

static inline int foo(int c)
{
  if (c < 4)
    return c;
  else
    return 4;
}

int bar(int c)
{
  assert(c < 2);

  return foo(c);
}

With -DNDEBUG -O3, GCC will still generate the (c < 4) comparison even though I know it is not needed, because a precondition of the bar function is that c is 0 or 1. Without -DNDEBUG, GCC does remove the comparison because it is implied by the asserts - but of course you have the overhead of the asserts then (which is a lot more).

Is there a way to convey the variable range to GCC so it can be used for optimisation?

If CLang can do better on this, I could also consider switching compilers.

Upvotes: 3

Views: 232

Answers (1)

You might use __builtin_unreachable (read about other builtins) in a test to tell the compiler, e.g.,

if (x<2 || x>100)
    __builtin_unreachable();
// Here the compiler knows that x is between 3 and 99 inclusive

In your case, add this at the start of your bar (probably wrapped in some nice looking macro):

if (c >= 2)
    __builtin_unreachable();

If you optimize strongly (e.g., -O2 at least), the compiler knows that x is between 3 and 99 (and recent versions of GCC contain code to do such analysis—at least processing simple constant interval constraints like above—and take advantage of them in later optimization passes).

However, I am not so sure that you should use that! (at least don't use it often and wrap that in some assert-like macro), because it might not worth the trouble, and because the compiler is in practice only able to handle and propagate simple constraints (whose details are compiler version specific).

As far as I know, both recent Clang and GCC accepts that builtin.

Also look into __builtin_trap (which also emits runtime code).

Upvotes: 3

Related Questions