Say I have following C function:
i64 my_comparator1(i64 x, i64 y)
{
if (x > y) { return 1; }
if (x < y) { return -1; }
return 0;
}
If I happen to know something about arguments that compiler doesn't know, I can use __builtin_unreachable:
i64 my_comparator2(i64 x, i64 y)
{
if (!((x <= 100) && (x >= -100)) __builtin_unreachable();
if (!((y <= 100) && (y >= -100)) __builtin_unreachable();
if (x > y) { return 1; }
if (x < y) { return -1; }
return 0;
}
Now, I want to convey to the compiler that only sign of the return value is important, so it is valid to transform the program into this (signed over/under-flow is UB already):
i64 my_comparator(i64 x, i64 y) { return x - y; }
Sure, the caller can easily tell the difference, but is there any way to explain to the compiler that I am okay with it?
I don't need portability, gcc-specific or clang-specific solution for x86-64 linux is just fine.
UPD: The code above is just example, it is not about particular transformation, it is about telling the compiler that
The code as written returns value X, but feel free to return any other value that satisfies the predicate P instead.
I don't think this is possible. We do have __builtin_unreachable()
to tell the compiler "you may do anything you want", but I don't think any compiler provides more general mechanisms to say "you may do anything within the following constraints" (e.g. return any number whose sign matches the sign of x-y
). And without that, the compiled function has to return the value it's told to.
That said, you can probably achieve much of your goal if you simply ensure that this function can always be inlined. If the compiler can see all the places where the result is used, it can optimize accordingly, and perhaps avoid some of the work. For instance, if you write something like
if (my_comparator1(x,y) > 0)
fum();
then the compiler can branch directly on the result of the compare, without having to actually materialize the value 1 in a register. It also does not need to execute a test to distinguish between the cases x < y
and x == y
, since they both result in the same branch being taken. Try on godbolt.