超过 INT_MAX 次迭代的 Openmp - 它合法吗?

Openmp with more than INT_MAX iterations - is it legal?

这是一个运行良好的循环:

#include <inttypes.h>
#include <iostream>
int main() {
  for (int32_t i = -2; i < INT32_MAX-2; i++) {
    std::cout << i << std::endl;
  }
}

添加 omp parallel for 子句似乎通过引入 int 溢出来破坏代码。

#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;
  }
}

对于 clang-10 和 gcc-10,程序都没有输出。另一方面,clang-12 似乎处理得当。

clang-10 至少会产生一些警告:

> 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]

这是 openmp 标准的合法、明确定义的行为还是实现错误?

#pragma omp parallel for 会导致 omp_get_num_threads() 循环计数的执行流程,类似于:

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;

第二个和更多线程将导致有符号整数溢出。

OpenMP 循环需要在开始循环之前计算迭代次数,因此循环变量的类型需要能够表达该次数。除此之外,OMP 标准允许有符号和无符号整数类型,没有任何限制。

OpenMP 标准不包含任何关于循环变量溢出的内容,所以我认为程序员有责任确保它不会发生。请注意,如果使用 collapse 子句(例如 ),则很容易发生这种情况。

这不是编译器中的错误,而是 OpenMP 中的未指定行为。 参见 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.

可以在 Microsoft 站点 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.

因此计算在 int 中完成,导致整数溢出 UB