我有一个定义为
的函数inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
v3 = _mm512_add_pd(v1, v2);
}
(__m512d
是映射到Intel MIC架构上的SIMD寄存器的本机数据类型)
由于此函数相当短并且经常被调用,我希望在每次调用时都内联它。但即使在我使用-inline-forceinline
和-O3
选项之后,英特尔的编译器似乎也不愿意内联此函数。据报道,“Forceinline”并未因电话而受到表彰...'在编译时。因为我必须使用一些编译器特定的功能,例如__m512d
类型,英特尔编译器是我唯一的选择。
更多信息:
文件结构非常简单。函数vec_add
在头文件mic.h
中定义,该文件包含在另一个文件test.cc
中。函数vec_add
只是在循环中重复调用,并且没有涉及函数指针。 test.cc
中代码的简化版本如下所示
for (int i = 0; i < LENGTH; i += 8) {
// a, b, c are arrays of doubles, and each SIMD register can hold 8 doubles
__mm512d va = _mm512_load_pd(a + i); // load SIMD register from memory
__mm512d vb = _mm512_load_pd(b + i); // ditto
__mm512d vc;
vec_add(vc, va, vb); // store SIMD register to memory
_mm512_store_pd(c + i, vc);
}
我已经尝试了各种提示,例如__attribute__((always_inline))
,__forceinline
和编译器选项-inline-forceinline
,但这些提示都没有。
完整代码
我已将所有相关代码以简化形式放在一起。如果您有英特尔编译器,可以尝试一下。使用选项-Winline
查看内联报告,使用-inline-forceinline
强制内联。
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
#define LEN (1<<20)
__attribute((target(mic)))
inline void vec_add(__m512d &v3, const __m512d &v1, const __m512d &v2) {
v3 = _mm512_add_pd(v1, v2);
}
int main() {
#pragma offload target(mic)
{
double *a = (double*)_mm_malloc(LEN*sizeof(double), 64);
double *b = (double*)_mm_malloc(LEN*sizeof(double), 64);
double *c = (double*)_mm_malloc(LEN*sizeof(double), 64);
for (int i = 0; i < LEN; i++) {
a[i] = (double)rand()/RAND_MAX;
b[i] = (double)rand()/RAND_MAX;
}
for (int i = 0; i < LEN; i += 8) {
__m512d va = _mm512_load_pd(a + i);
__m512d vb = _mm512_load_pd(b + i);
__m512d vc;
vec_add(vc, va, vb);
_mm512_store_pd(c + i, vc);
}
_mm_free(a);
_mm_free(b);
_mm_free(c);
}
}
配置
-O3 -inline-forceinline -Winline
你知道为什么这个功能不能被内联吗? 毕竟我怎么能把它内联起来(我不想转向宏)?
答案 0 :(得分:9)
出于某种原因,英特尔编译器没有在卸载的代码中内联函数(我不是很熟悉这个概念,所以我不知道这是什么技术原因)。 有关详细信息,请参阅effective-use-of-the-intel-compilers-offload-features(仅搜索“内联”)。
引用链接文章:
函数内联到卸载构造
有时,为了获得最佳性能,必须内联函数 生成的代码。 直接在#pragma offload 中调用的函数 编译器不会内联,即使它们被标记为内联。至 可以手动实现卸载区域中代码的最佳性能 内联函数,或将整个卸载构造放入其自身 功能
...
一种解决方案是手动内联函数f,如函数所示 V2
另一种解决方案是将卸载构造移动到自己的构造中 功能如功能v3所示。
如果我理解正确的话,最好的办法就是将循环放在一个单独的函数中,该函数也标有__attribute((target(mic)))。