在 gcc 中使用向量内在函数对常规数组进行别名

Posted

技术标签:

【中文标题】在 gcc 中使用向量内在函数对常规数组进行别名【英文标题】:Aliasing regular array with vector intrinsics in gcc 【发布时间】:2017-07-25 14:12:38 【问题描述】:

我正在研究 GCC 中的向量内在函数,特别是对于 AVX,我很想写这样的东西来在两个数组之间进行向量乘法:

#include <unistd.h>

void __attribute__((target("avx"))) vmul(float* __restrict__ cc, const float* __restrict__ aa, const float* __restrict__ bb, ssize_t size) 
    const ssize_t VECSIZE=8;
    typedef float vfloat __attribute__((vector_size(sizeof(float)*VECSIZE)));

    // duff's device, process any remainder up front
    ssize_t rem = size % VECSIZE;
    switch (rem) 
        case 7: cc[6] = aa[6]*bb[6]; /* FALLTHRU */
        case 6: cc[5] = aa[5]*bb[5]; /* FALLTHRU */
        case 5: cc[4] = aa[4]*bb[4]; /* FALLTHRU */
        case 4: cc[3] = aa[3]*bb[3]; /* FALLTHRU */
        case 3: cc[2] = aa[2]*bb[2]; /* FALLTHRU */
        case 2: cc[1] = aa[1]*bb[1]; /* FALLTHRU */
        case 1: cc[0] = aa[0]*bb[0]; /* FALLTHRU */
        case 0: break;
    
    size -= rem;

    // process rest of array
    const vfloat *va = (const vfloat*)(aa+rem);
    const vfloat *vb = (const vfloat*)(bb+rem);
    vfloat *vc = (vfloat*)(cc+rem);

    for (ssize_t ii=0; ii < size; ii++) 
        vc[ii] = va[ii]*vb[ii];
        


int main() 

问题在于将数据放入向量类型所需的指针别名。 GCC 很乐意让你这样做(没有警告 -Wall -Wextra -ansi -pedantic),但随后假设底层内存对齐是合适的。所以它在内循环中生成 vmovaps 指令:

   0x0000000000400660 <+176>:   vmovaps (%rsi,%rax,1),%ymm0
   0x0000000000400665 <+181>:   vmulps (%rdx,%rax,1),%ymm0,%ymm0
   0x000000000040066a <+186>:   vmovaps %ymm0,(%rdi,%rax,1)
   0x000000000040066f <+191>:   add    $0x20,%rax
   0x0000000000400673 <+195>:   cmp    %r8,%rax
   0x0000000000400676 <+198>:   jne    0x400660 <_Z4vmulPfPKfS1_l+176>

这很好,直到您传入一些未对齐的内存(或者在我的情况下,它的大小不是 8 的倍数),然后它会愉快地对您的程序进行分段错误,尝试使用对齐的指令加载未对齐的内存。

是否有适当的方法来使用矢量扩展来做到这一点?

【问题讨论】:

【参考方案1】:

你可以这样reduce the alignment:

typedef float vfloat __attribute__((vector_size(sizeof(float)*VECSIZE),
    aligned(4)));

通过该更改,我收到了vmovups 说明。

【讨论】:

果然,好像可以了。我想这就是我需要的!

以上是关于在 gcc 中使用向量内在函数对常规数组进行别名的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中使用英特尔内在函数加载和存储复杂的浮点数

使用intel内在函数加载内存中等距的双精度数?

为啥 gcc -O3 处理 avx256 的内在比较与 gcc -O0 和 clang 不同?

matmul 内在函数的 Fortran 数组排名

移植 InterlockedExchange,仅使用 GCC 内在函数

扩展除法/乘法的 gcc 内在函数