LLVM和gcc之间的SIMD向量互操作性

时间:2013-01-17 17:54:55

标签: gcc llvm vectorization simd abi

我想通过使用LLVM的JIT动态生成代码来加速我正在开发的程序。该算法可以对向量进行操作,我宁愿在LLVM中使用SIMD向量扩展来实现这一点(不仅可以使某些操作更快,而且实际上使代码生成更简单)。

我是否有机会以合理的便携方式完成这项工作?

在C方面,我将使用gcc,clang或者icc进行编译。我的向量将是简单的float x 4double x 4个东西。这个世界中非平台特定向量操作的事实标准似乎是gcc向量扩展:

typedef double Vector4 __attribute__ ((vector_size (sizeof(double)*4)));

检查生成的代码表明clang会在寄存器中传递double x 4向量,而gcc想要它在堆栈上 - 这很糟糕。 (它们都在寄存器中传递float x 4个向量。)

我的理解是这两个系统应该是ABI兼容的,但显然矢量不计算在内。我真的可以这样做吗?

我的示例程序是::

typedef double real;
typedef real Vector4 __attribute__ ((vector_size (sizeof(real)*4)));

Vector4 scale(Vector4 a)
{
    Vector4 s = {2, 2, 2, 2};
    return a*s;
}

将LLVM编译为:

scale:
    movapd  .LCPI0_0(%rip), %xmm2
    mulpd   %xmm2, %xmm0
    mulpd   %xmm2, %xmm1
    ret

...但是gcc产生了这个恐怖:

scale:
    subq    $64, %rsp
    movq    %rdi, %rax
    movsd   .LC0(%rip), %xmm0
    movapd  72(%rsp), %xmm1
    movsd   %xmm0, -56(%rsp)
    movsd   %xmm0, -48(%rsp)
    movsd   %xmm0, -72(%rsp)
    movsd   %xmm0, -64(%rsp)
    mulpd   -56(%rsp), %xmm1
    movapd  88(%rsp), %xmm0
    mulpd   -72(%rsp), %xmm0
    movapd  %xmm1, -104(%rsp)
    movq    -104(%rsp), %rdx
    movapd  %xmm1, -24(%rsp)
    movapd  %xmm0, -8(%rsp)
    movq    %rdx, (%rdi)
    movq    -16(%rsp), %rdx
    movq    %rdx, 8(%rdi)
    movq    -8(%rsp), %rdx
    movq    %rdx, 16(%rdi)
    movq    (%rsp), %rdx
    movq    %rdx, 24(%rdi)
    addq    $64, %rsp
    ret

如果我将real重新定义为float,我会从两个编译器(它们产生相同的代码)中得到这个:

scale:
    mulps   .LCPI0_0(%rip), %xmm0
    ret

这些都是用$CC -O3 -S -msse test.c编译的。

更新:我突然想到,简单的解决方案就是使用LLVM创建一个从结构转换为向量的蹦床,反之亦然。通过这种方式,互操作性问题被简化为按值传递的结构,其中被ABI确定为;向量仅存在于LLVM-land中。这意味着我只能在LLVM中使用SIMD,但我可以忍受它。

但是,我仍然想知道上述答案;矢量很棒,我希望能够更多地使用它们。

更新更新:原来C传递结构的方式是疯狂的......呃,疯了!指针传递struct { double x, y, z; }; struct { float x, y, z }作为%xmm寄存器的传递:xy打包到第一个,z位于第二...

简单而不受欢迎它不是!

0 个答案:

没有答案