The 当前的 OpenMP 标准 http://www.openmp.org/mp-documents/openmp-4.5.pdf#subsection.2.8.2说关于declare simd
C/C++ 指令:
在函数上使用声明 simd 构造可以创建
相关函数的 SIMD 版本可用于
在 SIMD 循环中处理来自单次调用的多个参数
同时。
本章中给出了更多详细信息,但对该指令可以应用的函数类型似乎没有限制。
所以我的问题是,该指令是否可以安全地应用于inline
功能?
我这么问有两个原因:
- An
inline
function 是一个相当不寻常的函数,因为它通常直接内联在调用它的地方。因此它可能永远不会编译为独立函数,因此,declare simd
它的方面与可能的情况相当多余simd
封闭循环级别的指令。
- 我有这样的代码
inline
declare simd
函数,有时,出于某些模糊的原因,GCC 会抱怨它们在链接时的多重定义(名称被额外的字符破坏,表明这些是矢量化版本)。但如果我删除declare simd
指令,它可以很好地编译和链接。
到目前为止我还没有想太多,但现在我很困惑。这是我的一个错误吗(即使用declare simd
for inline
函数)或者是 GCC 生成二进制向量化版本的问题inline
函数并未能在链接时对它们进行排序?
EDIT:
有一个 GCC 编译器选项会有所不同。当启用内联时(使用-O3
例如),代码可以正常编译和链接。但是当编译时-O0
或与-O3 -fno-inline
,内联被禁用,链接失败,并且该函数的“多重定义”装饰有omp declare simd
指示。
EDIT 2:
感谢@Zboson 关于编译器标志的问题,我成功创建了一个重现器。这里是:
foobar.h:
#ifndef FOOBAR_H_
#define FOOBAR_H_
#include <cmath>
#pragma omp declare simd
inline double foo( double d ) {
return sin( cos( exp( d ) ) );
}
double bar( double *v, int len );
#endif
foobar.cc:
#include "foobar.h"
double bar( double *v, int len ) {
double sum = 0;
for ( int i = 0; i < len; i++ ) {
sum += foo( v[i] );
}
return sum;
}
simd.cc:
#include <iostream>
#include "foobar.h"
int main() {
const int len = 100;
double *v = new double[len];
for ( int i = 0; i < len; i++ ) {
v[i] = i;
}
double sum = 0;
#pragma omp simd reduction( +: sum )
for ( int i = 0; i < len; i++ ) {
sum += foo( v[i] );
}
std::cout << sum << " " << bar( v, len ) << std::endl;
delete[] v;
return 0;
}
汇编:
> g++ -fopenmp -g simd.cc foobar.cc
/tmp/ccI4e7ip.o: In function `_ZGVbN2v__Z3food':
foobar.h:7: multiple definition of `_ZGVbN2v__Z3food'
/tmp/cc4U8Qyu.o:foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVbM2v__Z3food':
foobar.h:7: multiple definition of `_ZGVbM2v__Z3food'
/tmp/cc4U8Qyu.o:foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVcN4v__Z3food':
foobar.h:7: multiple definition of `_ZGVcN4v__Z3food'
/tmp/cc4U8Qyu.o:foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVcM4v__Z3food':
foobar.h:7: multiple definition of `_ZGVcM4v__Z3food'
foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVdN4v__Z3food':
foobar.h:7: multiple definition of `_ZGVdN4v__Z3food'
foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVdM4v__Z3food':
foobar.h:7: multiple definition of `_ZGVdM4v__Z3food'
foobar.h:7: first defined here
collect2: error: ld returned 1 exit status
> c++filt _ZGVdM4v__Z3food
_ZGVdM4v__Z3food
> c++filt _Z3food
foo(double)
Gcc 版本 4.9.2 和 5.1.0 都给出了完全相同的问题,而 Intel 编译器版本 15.0.3 编译得很好。
最终编辑:
赫里斯托·伊利耶夫的评论 https://stackoverflow.com/questions/34091341/openmp-declare-simd-for-an-inline-function#comment55959437_34097496 and Z玻色子的问题 https://stackoverflow.com/q/34110703/5239503让我感到安慰的是,我的代码符合 OpenMP 标准,而且这是 GCC 中的一个错误。我将尝试使用我能找到的最新版本进行进一步测试,并在需要时进行报告。