Standalone loop collapsing in OpenMP

Viewed 113

I have a nested loop that looks as follows -

for(int i=0; i<limit1; i++)
{
    for(int j=0; j<limit2; j++){
       /*
          Code with Custom function calls, branching etc etc.

      */
  }
}

The inner and outer loop iterations are independent of each other. Since this loop cannot trivially be vectorized, I would like to collapse it into one huge iteration space so that it can be unrolled more efficiently, in the sense that, instead of unrolling only the inner loop, the combined iteration space can be unrolled.

I do not want to parallelize it. From my understanding, I do not think openmp provides a stand alone collapsing pragma like - #pragma omp collapse(2), rather the collapse clause is used in conjunction with other pragmas like simd or for.

Can acheive this via OpenMP, or maybe some other method as well.

PS - I am not sure about the pros and cons of this method, whether one would get a significant performance increase etc. etc. If someone explain how can one (or for that matter if one can) theoretically(i.e. before benchmarking) ascertain this, it would be great.

TIA

1 Answers

First of all, OpenMP is "a model for parallel programming that is portable across architectures from different vendors" (source: OpenMP 5.1 specification). Thus, if you do not want to parallelize the loops, then it is probably not the right tool.

However, please note that OpenMP provide the directive unroll to fully or partially unrolls the outermost loop of a loop nest. The full clause to fully unroll a loop requires the iteration count (e.g. limit1) to be a compile-time constant (it is not theoretically possible otherwise anyway). The partial clause can be parametrized by an integer to control how many iterations are unrolled. As of now, neither GCC, ICC nor Clang support the two clauses.

There is also the tile directive that could reorder the iterations of your two nested loops so to get 2D fixed-size tiles. It does not specify to the compiler that the loop should be unrolled. Nevertheless, an aggressively-optimizing compiler will likely unroll the fixed-sized tile loop nest generally if it does not contain many branches or function calls (since it is often detrimental for the performance). This directive cannot be used in conjunction with unroll (because the tile loops do not have a canonical loop nest form).

Note that collapsing (manually or automatically using a tool) the two nested loops will certainly not help the compiler if the iteration counts are not a compile-time constants, and typically not if limit2 is not a power of two. Indeed, in such a case, using slow modulus by a variable or a rather-slow branch-less conditional move are certainly required. Unrolling such a loop would be very hard for the compiler (if even possible).

Related