13.11 Implementing FOR construct

  #pragma omp parallel for
  for (i = lb; i <= ub; i++)
    body;

becomes

  void subfunction (void *data)
  {
    long _s0, _e0;
    while (GOMP_loop_static_next (&_s0, &_e0))
    {
      long _e1 = _e0, i;
      for (i = _s0; i < _e1; i++)
        body;
    }
    GOMP_loop_end_nowait ();
  }

  GOMP_parallel_loop_static (subfunction, NULL, 0, lb, ub+1, 1, 0);
  subfunction (NULL);
  GOMP_parallel_end ();
  #pragma omp for schedule(runtime)
  for (i = 0; i < n; i++)
    body;

becomes

  {
    long i, _s0, _e0;
    if (GOMP_loop_runtime_start (0, n, 1, &_s0, &_e0))
      do {
        long _e1 = _e0;
        for (i = _s0, i < _e0; i++)
          body;
      } while (GOMP_loop_runtime_next (&_s0, _&e0));
    GOMP_loop_end ();
  }

Note that while it looks like there is trickiness to propagating a non-constant STEP, there isn’t really. We’re explicitly allowed to evaluate it as many times as we want, and any variables involved should automatically be handled as PRIVATE or SHARED like any other variables. So the expression should remain evaluable in the subfunction. We can also pull it into a local variable if we like, but since its supposed to remain unchanged, we can also not if we like.

For schedule(static) without ordered, the compiler uses:

  _Complex int GOMP_loop_static_worksharing (void)

which returns the thread id in the real part and the thread count in the imaginary part as a single value, avoiding separate omp_get_thread_num / omp_get_num_threads calls that OMPT cannot distinguish from user queries.

Similarly, for distribute constructs:

  _Complex int GOMP_distribute_static_worksharing (void)

returns the team id and team count.

There are separate routines for handling loops with an ORDERED clause. Bookkeeping for that is non-trivial...