Assume you have following C++ snippet:
// i, j, n are of type size_t
// we assume that i, j and n are not optimized away
if((n > 0) && (j < n))
{
size_t a = i * n +j;
size_t p = a / n;
size_t q = a % n;
// now do something with p and q
// a is never used afterwards
}
clang 16 and gcc 13.2 with -O2 and -O3 will produce assembly code that computes a
exactly as written above and then performs an integer division.
Here’s the thing though, it’s completely pointless. Ideally the compiler should be able to understand that inside that if
block, p
and q
are respectively always going to be equal to i
and j
without the need to even compute a
or do an integer division. So ideally, the compiler should optimize away a
and simply put p = i
and q = j
.
However, the compiler is not optimizing those away. So maybe it is being careful because i * n +j
may overflow? In that case, how would one indicate to the compiler that that won’t be a problem?
(the above code is obviously not written by hand in practice, I’d get that very often after inlining functions that manipulate matrix indices and it just frustrates me to see the compiler not understanding that lots pf arithmetic can be avoided)
Okay so far I got around this using clang’s
__builtin_assume
to enforce that(i * n + j) % n
is alwaysj
whenj < n
, and together with-O2
it works perfectly. I guess when C++23 is ready we could do the same using the[[assume(...)]]
attribute.You can already feature-test for assume (or gnu::assume) without C++23. See: https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#testing-for-the-presence-of-an-attribute-__has_cpp_attribute