clang OpenMP 循环继续计数超出循环条件限制

问题描述 投票:0回答:1

我有以下有趣的问题:

#include <iostream>
#include <omp.h>

using namespace std;

int main(const int, const char **) {

  const size_t n = 13; // triggers the issue
  // const uint32_t n = 13; // fixes the issue

#pragma omp parallel for
  for (uint32_t i = 0; i < n; i += 2) { // `+= 1` fixes the issue
    cerr << "i = " << i << ", n = " << n << endl;
  }

}

尽管我的

i < n
n = 13
这会在
clang++ -fopenmp
上打印无限系列的数字:

i = 0, n = 13
i = 2, n = 13
i = 4, n = 13
i = 6, n = 13
i = 8, n = 13
i = 10, n = 13
i = 12, n = 13     <- this should be impossible
i = 14, n = 13
...

怎么会这样?

clang++ 11、14 和 16 会发生这种情况,但 GCC 不会。如果删除

-fopenmp
也可以修复。

如果我这样做

+= 1
而不是
+= 2
,问题就会消失。

根据OPenMP循环增量,“循环增量大于1”是合法的。

如果我将

n
的类型从
size_t
更改为
uint32_t
,问题也会消失。

有关警告的观察

使用

-Wall
+= 2
clang++
打印这些警告:

clang-openmp-for-loop-test.cpp:49:3: warning: implicit conversion from 'unsigned long' to 'unsigned int' changes value from 9223372034707292167 to 2147483655 [-Wconstant-conversion]
  for (uint32_t i = 0; i < n; i += 2) {
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
clang-openmp-for-loop-test.cpp:49:3: warning: implicit conversion from 'unsigned long' to 'unsigned int' changes value from 9223372034707292167 to 2147483655 [-Wconstant-conversion]
  for (uint32_t i = 0; i < n; i += 2) {
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
clang-openmp-for-loop-test.cpp:49:3: warning: implicit conversion from 'unsigned long' to 'unsigned int' changes value from 9223372034707292167 to 2147483655 [-Wconstant-conversion]
  for (uint32_t i = 0; i < n; i += 2) {
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.

关于这些警告,我有很多不明白的地方:

  1. 为什么相同的警告(在相同的代码位置)发出 3 次?
  2. 价值
    9223372034707292167
    从何而来?这是一个
    -Wconstant-conversion
    警告,当然它应该警告我实际使用的一些常量。值
    2147483655
    maximum 32-bit-signed integer + 8
  3. 当我将
    += 2
    更改为
    += 1
    时,与类型相关的警告如何消失?这两个文字的 type 肯定是相同的吗?

环境

Ubuntu 22.04。

sudo apt install clang14 libomp-14-dev gcc+12 libstdc++-12-dev

(需要

gcc+12 libstdc++-12-dev
才能使
#include <iostream>
工作,因为 clang 使用 GCC 的 stdlib 标头。)

编译:

clang++ myprogram.cpp -o myprogram -fopenmp -O2 -Wall -Wextra

运行:

OMP_NUM_THREADS=1 ./myprogram 2>&1 | head -n20

编译器错误,或者我遗漏了什么?

clang openmp clang++
1个回答
0
投票

将测试更改为显式转换

i < (uint32_t)n
修复了 clang 的问题 (17)。

但是显式转换

(size_t)i < n
会导致编译错误:

condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', '>=', or '!=') of loop variable 'i'
.

我不太清楚,但我对 OpenMP 5.2 规范(最新的,但我不知道 clang 使用哪一个)的理解是,C/C++ OpenMP 循环的测试表达式应涉及变量

i
单独在左侧或右侧(规范第88页):

因为

i
n
是不同的类型,编译器必须隐式转换其中之一,并且因为
n
具有更广泛的范围,所以转换的是
i
。那么测试不再单独涉及
i
,而是涉及
i
的函数。

所以,最初的问题可能是这是一个非法的 OpenMP 代码,即使 gcc 将其作为 OpenMP 规范的扩展来处理。尽管如此,这也是一个 clang 编译器错误:clang 最初进入隐式转换路由,然后弄乱循环(它应该因为非法代码而产生编译错误,或者像 gcc 那样将其作为扩展处理)。

© www.soinside.com 2019 - 2024. All rights reserved.