缺少 SIMD 指令的 OpenMP if 子句

Lack of OpenMP if clause for SIMD directive

我正在开发一些并行 C++ 模拟代码,我希望尽可能有效地对其进行矢量化。这就是我同时使用模板参数和 OpenMP SIMD 指令的原因:

我的意思的一个(愚蠢的)例子如下:

template< bool checkNeeded >
int ratio( double *res, double *num, double *denom, int n ) {
    #pragma omp simd
    for ( int i = 0; i < n; i++ ) {
        if ( checkNeeded ) { // dead code removed by the compiler when template is false
            if ( denom == 0 ) {
                std::cout << "Houston, we've got a problem\n";
                return i;
            }
        }
        res[i] = num[i] / denom[i];
    }
    return n;
}

在全球范围内,它工作得很好,但我遇到的麻烦是,在(非常罕见的)我想使用代码的 ratio<true>() 版本的情况下,这个代码已经被编译器矢量化了因为 #pragma omp simd 指令,由于测试、打印和提前退出循环,它比非矢量化版本慢得多…… 所以我需要的是在我的 simd 指令中添加一个 if 子句,指示编译器何时服从该指令。那会给出这样的东西:

#pragma omp simd if( checkNeeded == false )

不幸的是,尽管许多 OpenMP 指令都支持这样的 if 子句,但 simd 不支持...我不认为我的请求是完全愚蠢的,所以我想知道为什么是这样吗,以后有没有可能支持。 有人知道吗?

扩展 user3528438 的评论,这可能是将您的函数拆分为两个不同函数的最合乎逻辑的地方之一。一个处理 false 情况并按照您的方式编写,另一个处理 true 情况并且没有 simd 命令。

或者,如果你坚持使用一个函数,你可以很容易地写

template< bool checkNeeded >
int ratio( double *res, double *num, double *denom, int n ) {
    if (!checkNeeded) {
        #pragma omp simd
        for ( int i = 0; i < n; i++ ) {
            res[i] = num[i] / denom[i];
        }
        return n;
    } else {
        for ( int i = 0; i < n; i++ ) {
            if ( denom == 0 ) {
                std::cout << "Houston, we've got a problem\n";
                return i;
            }
            res[i] = num[i] / denom[i];
        }
        return n;
    }
}

这将比 false 情况下的初始函数稍慢,因为有一个 if 语句要评估(假设 n 很大 [甚至大于 10 而你不是一个重要因素)不应该注意到减速])。此外,在 true 情况下它会快得多,因为您不必在每次迭代时都评估第一个 if 语句。

template< bool checkNeeded >
int ratio( double *res, double *num, double *denom, int n );// c++ declaration

template<>int ratio<true>( double *res, double *num, double *denom, int n ) 
{

    for ( int i = 0; i < n; i++ ) {
        res[i] = num[i] / denom[i];
    }
    return n;
}

template<>int ratio<false>( double *res, double *num, double *denom, int n ) {
    for ( int i = 0; i < n; i++ ) {
        if ( denom == 0 ) {
            std::cout << "Houston, we've got a problem\n";
            return i;
        }
        res[i] = num[i] / denom[i];
        }
    return n;
}

How do I explicitly instantiate a template function?

I don't think my request is completely stupid so I wonder why it is so, and whether it is likely to be supported in the future. Anybody knows about that?

SIMD 指令会影响编译时的代码生成,而其他 OpenMP 构造上的 "if" 子句会实现 运行 时测试。 ("if" 条件不是编译时常量)。因此,要在 SIMD 子句上实现 "if",通常需要编译器克隆循环体并生成两个不同的版本,然后选择哪个在 运行 时动态执行。

对于一个非常罕见的案例来说,这似乎需要付出很多努力,所以我怀疑它是否会成为标准。 (而且,无论如何,在这一点上,您可以寻找的第一个标准在几年内不会出现,因此您可能需要更实用的修复:-))