For example, let's take one critical function here: bit reversal. The C code provided (renamed variables so it's easy to consistently compare) has an impressive speedup just going from -O1 to higher optimization levels. And then, on top of that speedup with a decent optimizer, we can again halve the amount of time spent in this function by providing better intentions to the compiler which allow it to perform automatic vectorization. Note this is all in standard C, and makes the code simpler to understand (and maintain) by humans as well.
uint64_t reverse_slow(uint64_t n, uint64_t k)
{
uint64_t r, i;
for (r = 0, i = 0; i < k; ++i, n >>= 1)
r = (r << 1) | (n & 1);
return r;
}
uint64_t reverse_fast(const uint64_t n, const uint64_t k)
{
uint64_t r, i;
for (r = 0, i = 0; i < k; ++i)
r |= ((n >> i) & 1) << (k - i - 1);
return r;
}
Lesson: do your job as a human and provide guidance, let the machines do their job at taking your advice and running wild with creativity. It helps you both become more effective.