【发布时间】:2015-12-04 15:08:11
【问题描述】:
current OpenMP standard 表示 C/C++ 的 declare simd 指令:
在函数上使用 declare simd 构造可以创建 相关函数的 SIMD 版本,可用于 在 SIMD 循环中处理来自单个调用的多个参数 同时。
更多细节在本章中给出,但该指令可以应用于的函数类型似乎没有限制。
所以我的问题是,这个指令可以安全地应用于inline 函数吗?
我问这个有两个原因:
-
inline函数是一个相当不寻常的函数,因为它通常直接内联在它被调用的地方。因此,它可能永远不会编译为独立函数,因此,它的declare simd方面与封闭循环级别可能的simd指令相当多余。 - 我有一个带有
inlinedeclare simd函数的代码,有时,由于一些模糊的原因,GCC 抱怨它们在链接时的多重定义(名称带有额外的字符,表明这些是矢量化版本)。但是如果我删除declare simd指令,它会编译并链接正常。
到目前为止,我还没有想太多,但现在我很困惑。这是我的一个错误(即使用declare simd 处理inline 函数)还是GCC 生成inline 函数的二进制矢量化版本并且未能在链接时对其进行排序的问题?
编辑:
有一个 GCC 编译器选项会有所不同。当启用内联时(例如-O3),代码编译和链接正常。但是,当使用-O0 或-O3 -fno-inline 编译时,内联被禁用,并且链接失败,并且使用omp declare simd 指令修饰的函数的“多重定义”。
编辑 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 编译它就好了。
最终编辑:
Hristo Iliev's comment 和 Z boson's question 安慰我,我的代码符合 OpenMP,这是 GCC 中的一个错误。我会用我能找到的最新版本进行进一步测试,并在需要时报告。
【问题讨论】:
-
“所以它可能永远不会编译为独立函数......”不太确定。
-
失败时使用了哪些编译选项?
-
使用
-O2而不是-O3或-Ofast会发生什么? -
嗯。好吧,我的想法就这么多,但这仍然很有趣。也许这与
omp simd和-Ofast启用的新 SIMD 数学函数有关? -
@VladimirF 是的,我也不确定。进一步的测试表明,确实,问题出在函数没有被内联。