Reputation: 401
Here is a loop that works perfectly fine:
#include <inttypes.h>
#include <iostream>
int main() {
for (int32_t i = -2; i < INT32_MAX-2; i++) {
std::cout << i << std::endl;
}
}
Adding omp parallel for
clause seems to break the code by introducing int overflow.
#include <inttypes.h>
#include <iostream>
int main() {
#pragma omp parallel for
for (int32_t i = -2; i < INT32_MAX; i++) {
std::cout << i << std::endl;
}
}
For both clang-10 and gcc-10 the program produces no output. clang-12 on the other hand seems to handle it properly.
clang-10 at least produces some warnings:
> clang++-10 int_div.cpp -Wall -fopenmp
int_div.cpp:133:3: warning: overflow in expression; result is -2147483647 with type 'int' [-Winteger-overflow]
for (int i = -2; i < INT32_MAX; i++) {
^
int_div.cpp:133:3: warning: overflow in expression; result is 2147483646 with type 'int' [-Winteger-overflow]
int_div.cpp:133:3: warning: overflow in expression; result is -2147483647 with type 'int' [-Winteger-overflow]
int_div.cpp:133:3: warning: overflow in expression; result is -2147483647 with type 'int' [-Winteger-overflow]
int_div.cpp:133:3: warning: overflow in expression; result is -2147483647 with type 'int' [-Winteger-overflow]
Is this a legal, well defined behavior of openmp standard or an implementation bug?
Upvotes: 1
Views: 148
Reputation: 14157
It's not a bug in a compiler but rather unspecified behavior in OpenMP. See 2.9.1 Canonical Loop Form
If var is of an integer type, then the type is the type of var.
...
The behavior is unspecified if any intermediate result required to compute the iteration count cannot be represented in the type determined above.
A similar wording can be found on Microsoft site at 241-for-construct:
This computation is made with values in the type of var, after integral promotions. In particular, if value of b - lb + incr can't be represented in that type, the result is indeterminate.
Therefore the computation is done in int
resulting in integer overflow thus UB.
Upvotes: 1
Reputation: 2818
The OpenMP standard does not contain anything about overflow of loop variable(s), so I think it is the programmer's responsibility to make sure it will not happen. Note that it can happen easily if the collapse
clause is used (e.g. see this example).
Upvotes: 0
Reputation: 5810
OpenMP loops need to compute the number of iterations before starting the loop, so the type of the loop variable needs to be such that the number is expressible. Other than that, the OMP standard allows both signed and unsigned integer types, with no restriction indicated.
Upvotes: 0
Reputation: 38773
#pragma omp parallel for
would result in the
execution flow with omp_get_num_threads()
for loop count, something like:
for (int32_t i = -2; i < INT32_MAX; i += omp_get_num_threads())
std::cout << i << std::endl;
for (int32_t i = -1; i < INT32_MAX; i += omp_get_num_threads())
std::cout << i << std::endl;
// ...
for (int32_t i = -2 + omp_get_thread_num() - 1; i < INT32_MAX; i += omp_get_num_threads())
std::cout << i << std::endl;
The second and further threads would result in signed integer overflow.
Upvotes: 0