无法使用英特尔编译器强制内联C++函数

12

我有一个函数定义如下:

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选项,Intel的编译器似乎仍不愿意将该函数内联。在编译时,它报告“Forceinline not honored for call ...”。由于我必须使用一些编译器特定功能,例如__m512d类型,因此Intel编译器是我的唯一选择。

更多信息:

文件结构非常简单。函数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);
    }
}

配置

  • 编译器: Intel编译器(ICC) 14.0.2
  • 编译选项: -O3 -inline-forceinline -Winline

您有什么想法,为什么这个函数无法内联呢? 而我怎样才能在最终将其内联(我不想使用宏)?


3
你在同一个模块中调用这个函数吗? - urzeit
请展示给我们调用点。 - MikeMB
2
你是否检查了汇编代码,确保真的有跳转到你的函数? - MikeMB
2
@MikeMB 我还没有检查汇编代码。但我已经尝试将此函数转换为宏,并获得了明显的性能提升。因此,我相当确定该函数未被内联。 - lei_z
1
@lei.april 听起来很合理,但不幸的是,我不知道为什么编译器不想内联这个函数。 然而,由于您已经在函数接口中使用了特定于编译器的类型,我想知道为什么您首先要将对 _mm512_add_pd 的调用放在一个函数中? - MikeMB
显示剩余20条评论
1个回答

9
由于某些原因,英特尔编译器在卸载代码中不会将函数内联(我对这个概念不太熟悉,所以不知道其技术上的原因)。
更多信息请参见effective-use-of-the-intel-compilers-offload-features (搜索“inline”即可)。
引用链接文章中的内容:
函数内联到卸载构造物中
有时为了生成代码的最佳性能,需要将函数内联。即使将函数标记为内联,在#pragma offload 中直接调用的函数也不会被编译器内联。为了在卸载区域中实现最佳性能,请手动内联函数或将整个卸载构造物放置到其自己的函数中。
一种解决方案是手动内联函数f,如v2示例中所示。
另一种解决方案是将卸载构造移动到其自己的函数中,如v3示例所示。
如果我理解正确,对您来说最好的方法是将循环放入一个也带有__attribute((target(mic)))标记的单独函数中。

1
我认为这只是当前实现的限制,而不是设计意图。 - pburka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接