c++cboostmacrosloop-unrolling

Self-unrolling macro loop in C/C++


I am currently working on a project, where every cycle counts. While profiling my application I discovered that the overhead of some inner loop is quite high, because they consist of just a few machine instruction. Additionally the number of iterations in these loops is known at compile time.

So I thought instead of manually unrolling the loop with copy & paste I could use macros to unroll the loop at compile time so that it can be easily modified later.

What I image is something like this:

#define LOOP_N_TIMES(N, CODE) <insert magic here>

So that I can replace for (int i = 0; i < N, ++i) { do_stuff(); } with:

#define INNER_LOOP_COUNT 4
LOOP_N_TIMES(INNER_LOOP_COUNT, do_stuff();)

And it unrolls itself to:

do_stuff(); do_stuff(); do_stuff(); do_stuff();

Since the C preprocessor is still a mystery to me most of the time, I have no idea how to accomplish this, but I know it must be possible because Boost seems to have a BOOST_PP_REPEAT macros. Unfortunately I can't use Boost for this project.


Solution

  • You can use templates to unroll. See the disassembly for the sample Live on Godbolt

    enter image description here

    But -funroll-loops has the same effect for this sample.


    Live On Coliru

    template <unsigned N> struct faux_unroll {
        template <typename F> static void call(F const& f) {
            f();
            faux_unroll<N-1>::call(f);
        }
    };
    
    template <> struct faux_unroll<0u> {
        template <typename F> static void call(F const&) {}
    };
    
    #include <iostream>
    #include <cstdlib>
    
    int main() {
        srand(time(0));
    
        double r = 0;
        faux_unroll<10>::call([&] { r += 1.0/rand(); });
    
        std::cout << r;
    }