10

In the following code, only one comparison will be done, because the compiler knows the conditions are exclusive and we will always enter the second condition as bar will be necessary > 32:

int foo(int bar) {
    if (bar <= 64)
        return 1;
    if (bar > 32) {
        printf("Too many elements");
    }
    return 0;
}

Now, imagine I know bar is always higher than 64. Because of the input of the system, configuration, or else. How can I hint the compiler to do no comparison at all, like if the if (bar <= 64) return was compiled, except it actually isn't kept in the final ASM.

Something like:

int foo(int bar) {
    @precond(bar > 64);
    if (bar > 32) {
        printf("Too many elements");
    }
    return 0;
}

Is my only solution to write eg a LLVM pass?

MappaM
  • 809
  • 8
  • 15
  • 1
    What for? IMO X-Y problem. – 0___________ Mar 01 '20 at 12:32
  • 1
    I don't think the specifics are needed here, it's for high-speed networking optimization. Specializing code according to the predicted input. I slightly changed the problem to make it more clear and state the input. – MappaM Mar 01 '20 at 12:36
  • I think you can use GCC's `__builtin_expect`: http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html – ForceBru Mar 01 '20 at 12:43
  • 1
    Thanks @ForceBru but that is only a hint, and will keep the branch. It will just ensure that the most probable code is not on the jumped path. I want to remove the jump part. I would like __builtin_enforced maybe :p – MappaM Mar 01 '20 at 12:46
  • Note that writing a pass is really, really simple. – arnt Mar 01 '20 at 15:03

1 Answers1

11

You can use __builtin_unreachable in GCC:

if (bar > 32) {
  __builtin_unreachable();
}

__builtin_assume in Clang:

__builtin_assume(bar <= 32);

and __assume in MSVC:

__assume(bar <= 32);

With C++23 you could also use portable syntax

[[assume(bar <= 32)]];
yugr
  • 19,769
  • 3
  • 51
  • 96
  • Yes, it works! I verified with gcc -S and there is not any comparison anymore. – MappaM Mar 01 '20 at 13:07
  • 11
    Maybe I'm missing something obvious, but your two examples seem like opposites: the GCC example is declaring that `bar <= 32` is *false*, while the MSVC example is declaring that `bar <= 32` is *true*. No? – ruakh Mar 01 '20 at 22:59
  • @ruakh Yikes! Fixed. – yugr Mar 02 '20 at 04:21
  • 1
    In clang you should use `__builtin_assume`, even though `__builtin_unreachable` is available - the latter won't cause the optimiser to omit code, but the former will. – user7761803 Mar 05 '20 at 09:04
  • @user7761803 I have seen `__builtin_unreachable` on clang result in omitted code. IMO, `__builtin_assume(Cond)` should be equivalent to `do if(!(Cond)) __builtin_unreachable(); while(0)` – Petr Skocik Mar 28 '23 at 14:49