constexpr for loop?

2,009 views
Skip to first unread message

Evan Teran

unread,
Jun 24, 2017, 8:12:58 PM6/24/17
to ISO C++ Standard - Future Proposals
I was just thinking the other day. Now that we are getting constexpr if, what else could we allow at compile time? What occurs to me is that we could have a nice compile time means to do loop unrolling. What I imagine is something like this:


constexpr for(int i = 0; i < 4; ++i) {
    whatever
();
}


would cause the compile to simply emit:

whatever();
whatever
();
whatever
();
whatever
();

Obviously the loop bounds would have to be trivially known at compile time for this to work, and should throw a hard error if it isn't. Many compilers already are doing this analysis that would enable this, so why not make that analysis able to be leveraged by the developer?

I know that the conventional wisdom is to just write the loop, and if the compiler deems it optimal to unroll the loop, then it will. But sometimes, people just know better.

I can imagine versions of many algorithms that are functionally identical the standard ones, but allow the user to specify how much to unroll via template parameters, like this (parden any typos):

namespace unrolled {

template <int N, class In, class Size, class F>
F for_each_n
(In first, Size Count, F fn) {
   
Size rounded = (count / N) * N; // round count down to nearest multiple of N
   
Size i = 0;


   
// do as much as possible in chunks of unrolled size N
   
while(i < rounded) {
       
constexpr for(int j = 0; j < N; ++j) {
            fn
(first[j]);
       
}
        i
+= N;
   
}


   
while(i < count) {
        fn
(first[i++]);
   
}
}

}

Which would enable code like this:

unrolled::for_each_n<3>(std::begin(arr), 30, [](auto elem) {
   
// do whatever with elem
}


It would be functionally the same as a regular std::for_each_n, but unrolled into blocks of size 3 as much as possible.

Thoughts? Is this just not worth the effort?
Evan

Nicol Bolas

unread,
Jun 25, 2017, 12:06:32 AM6/25/17
to ISO C++ Standard - Future Proposals
On Saturday, June 24, 2017 at 8:12:58 PM UTC-4, Evan Teran wrote:
I was just thinking the other day. Now that we are getting constexpr if, what else could we allow at compile time? What occurs to me is that we could have a nice compile time means to do loop unrolling.

No. If we're going to have `constexpr for`, then it should serve an actual semantic purpose, not merely be some syntactic sugar for a loop unrolling compiler hint.

After all, we didn't add `if constexpr` just so that we could make sure the condition was checked at compile-time instead of runtime. It exists to allow us to write code that would otherwise be il-formed in the not-taken branch. An optimizer can choose to check a condition at compile-time; an optimizer cannot choose to pretend that il-formed code is valid. You need actual syntax to make it so.

There have been several ideas and even proposals for `constexpr for`-type things that offer actual features, things the optimizer couldn't do. You should look at them.

Evan Teran

unread,
Jun 25, 2017, 2:18:12 AM6/25/17
to ISO C++ Standard - Future Proposals
That's fair enough, but I think that unrolling is just one of the things you could do with this, so that was the first example I gave. I could also imagine things like this:

constexpr for(int i = 0; i < 4; ++i) {

    templated_func
<i>();
}

which is more that just unrolling hinting. It is actually instantiating 4 instances of a template at compile time. Of course you can do all of these things with template recursion, but that gets messy really quickly.

peetp...@gmail.com

unread,
Jun 25, 2017, 4:39:11 PM6/25/17
to ISO C++ Standard - Future Proposals
It seems that this could be really useful, especially for static reflection.

And actually, there is a fork of clang by Andrew Sutton which basically implements the "constexpr" (evaluation/unrolling at compile-time) loop:


Reply all
Reply to author
Forward
0 new messages